diff --git a/apps/page/package.json b/apps/page/package.json index 2199db07f..70d17a308 100644 --- a/apps/page/package.json +++ b/apps/page/package.json @@ -38,7 +38,8 @@ "scroll-into-view-if-needed": "3.1.0", "vue-i18n": "9.13.1", "ndarray": "1.0.19", - "quantize": "1.0.2" + "quantize": "1.0.2", + "@heroicons/vue": "2.2.0" }, "devDependencies": { "@types/lodash-es": "4.17.12", diff --git a/apps/page/public/favicon.svg b/apps/page/public/favicon.svg deleted file mode 100644 index f157bd1c5..000000000 --- a/apps/page/public/favicon.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/apps/page/public/icon.svg b/apps/page/public/icon.svg new file mode 100644 index 000000000..92c1cf905 --- /dev/null +++ b/apps/page/public/icon.svg @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/apps/page/src/features/PageFooter.vue b/apps/page/src/features/PageFooter.vue index 3d5952baa..8f84d62c3 100644 --- a/apps/page/src/features/PageFooter.vue +++ b/apps/page/src/features/PageFooter.vue @@ -23,10 +23,10 @@
{{ t('FOOTER.CREATED_WITH', { name: 'Podlove', buildDate }) }}{{ t('FOOTER.CREATED_WITH', { name: 'Podlove Lux', buildDate }) }}
diff --git a/apps/page/src/features/feed-search/FeedSearch.vue b/apps/page/src/features/feed-search/FeedSearch.vue new file mode 100644 index 000000000..771bdecb5 --- /dev/null +++ b/apps/page/src/features/feed-search/FeedSearch.vue @@ -0,0 +1,174 @@ + + + + + diff --git a/apps/page/src/features/feed-search/components/Fyyd.vue b/apps/page/src/features/feed-search/components/Fyyd.vue new file mode 100644 index 000000000..e33eb02fe --- /dev/null +++ b/apps/page/src/features/feed-search/components/Fyyd.vue @@ -0,0 +1,20 @@ + diff --git a/apps/page/src/features/feed-search/components/Item.vue b/apps/page/src/features/feed-search/components/Item.vue new file mode 100644 index 000000000..1d1de4015 --- /dev/null +++ b/apps/page/src/features/feed-search/components/Item.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/apps/page/src/features/feed-search/components/Search.vue b/apps/page/src/features/feed-search/components/Search.vue new file mode 100644 index 000000000..f9182d0aa --- /dev/null +++ b/apps/page/src/features/feed-search/components/Search.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/apps/page/src/lib/debounce-async.ts b/apps/page/src/lib/debounce-async.ts new file mode 100644 index 000000000..afc18fcf4 --- /dev/null +++ b/apps/page/src/lib/debounce-async.ts @@ -0,0 +1,22 @@ + +export function debounceAsync Promise>( + callback: Callback, + wait: number, +): (...args: Parameters) => Promise { + let timeoutId: number | null = null; + + return (...args: any[]) => { + if (timeoutId) { + clearTimeout(timeoutId); + } + + return new Promise((resolve) => { + const timeoutPromise = new Promise((resolve) => { + timeoutId = setTimeout(resolve, wait) as unknown as number; + }); + timeoutPromise.then(async () => { + resolve(await callback(...args)); + }); + }); + }; +} diff --git a/apps/page/src/lib/get-image-color.ts b/apps/page/src/lib/get-image-color.ts index fcee64a49..40f98fb18 100644 --- a/apps/page/src/lib/get-image-color.ts +++ b/apps/page/src/lib/get-image-color.ts @@ -8,7 +8,7 @@ const fetchImage = async ( ): Promise<{ data: ArrayBuffer; dimensions: { width: number; height: number } }> => new Promise((resolve, reject) => { const img = new Image(); - img.crossOrigin = 'anonymous'; + img.crossOrigin = 'Anonymous'; img.onload = function () { const canvas = document.createElement('canvas'); canvas.width = img.width; @@ -58,7 +58,7 @@ const convertToPixels = (pixels: ndarray.NdArray): quantize.RgbPixel[] => { const extractColors = ( pixels: quantize.RgbPixel[] ): { primaryColor: rgbColor | null; complementaryColor: rgbColor | null } => { - const colorPalette = quantize(pixels, 1); + const colorPalette = quantize(pixels, 2); if (!colorPalette) { return { primaryColor: null, complementaryColor: null }; @@ -77,6 +77,7 @@ const getImageColors = async ( .then(parseImage) .then(convertToPixels) .then(extractColors) + .catch(() => ({ primaryColor: null, complementaryColor: null })); export default getImageColors; diff --git a/apps/page/src/logic/sagas/layout.sagas.ts b/apps/page/src/logic/sagas/layout.sagas.ts index 1fdb7cf0d..4083bdae3 100644 --- a/apps/page/src/logic/sagas/layout.sagas.ts +++ b/apps/page/src/logic/sagas/layout.sagas.ts @@ -40,7 +40,6 @@ export default function ({ const tailwindColorTokens = (color: rgbColor | null): ColorTokens | null => { const tokens = [100, 200, 300, 400, 500, 600, 700, 800]; - console.log(color); if (!color) { return null; } @@ -57,7 +56,7 @@ export default function ({ return; } - const { primaryColor, complementaryColor } = yield getImageColors(poster); + const { primaryColor, complementaryColor } = yield getImageColors(`/api/proxy?url=${poster}`); const primary = tailwindColorTokens(primaryColor); const complementary = tailwindColorTokens(complementaryColor); diff --git a/apps/page/src/pages/api/feed.ts b/apps/page/src/pages/api/feed.ts new file mode 100644 index 000000000..577608b46 --- /dev/null +++ b/apps/page/src/pages/api/feed.ts @@ -0,0 +1,26 @@ +import feedParser from "../../logic/data/feed-parser"; + +export async function GET({ request }: { request: Request }) { + const url = new URL(request.url); + const feed = url.searchParams.get('url'); + + if (!feed) { + return new Response(null, { + status: 422, + statusText: 'Missing url parameter' + }); + } + + try { + const data = await feedParser({ feed }); + return new Response( + JSON.stringify(data) + ); + + } catch (err) { + return new Response(null, { + status: 422, + statusText: 'Invalid feed' + }); + } +} diff --git a/apps/page/src/pages/api/proxy.ts b/apps/page/src/pages/api/proxy.ts new file mode 100644 index 000000000..42541f903 --- /dev/null +++ b/apps/page/src/pages/api/proxy.ts @@ -0,0 +1,14 @@ +export async function GET({ request }: { request: Request }) { + const url = new URL(request.url); + const proxyUrl = url.searchParams.get('url'); + + if (!proxyUrl) { + return new Response(null, { + status: 422, + statusText: 'Missing url parameter' + }); + } + + const response = await fetch(proxyUrl); + return new Response(await response.arrayBuffer()); +} diff --git a/apps/page/src/pages/index.astro b/apps/page/src/pages/index.astro new file mode 100644 index 000000000..507ea3341 --- /dev/null +++ b/apps/page/src/pages/index.astro @@ -0,0 +1,68 @@ +--- +import { getLanguage } from '../i18n'; +import FeedSearch from '../features/feed-search/FeedSearch.vue'; +const lang = getLanguage(); +--- + + + + + + + + + + Podlove Lux + + + +
+
+

+ +
+ Podlove + Illuminate your Feed +
Lux +

+
+
+
+
+ +
+
+ + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e2bd06a96..9e495ddb9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -99,6 +99,9 @@ importers: '@astrojs/vue': specifier: 5.0.3 version: 5.0.3(@types/node@18.18.14)(astro@5.1.1)(vue@3.5.12) + '@heroicons/vue': + specifier: 2.2.0 + version: 2.2.0(vue@3.5.12) '@m31coding/fuzzy-search': specifier: 1.0.1 version: 1.0.1 @@ -2972,6 +2975,14 @@ packages: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} dev: true + /@heroicons/vue@2.2.0(vue@3.5.12): + resolution: {integrity: sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw==} + peerDependencies: + vue: '>= 3' + dependencies: + vue: 3.5.12(typescript@5.3.2) + dev: false + /@histoire/app@0.16.1(vite@4.3.9): resolution: {integrity: sha512-13komnhVk1Pk0wMmkJKDPWT8RKpA5HfAbeeXSHAq29pvFP9Faq+dAa62g1wqOpoyJD5C7SkI0OPI3eJwJHgTiQ==} dependencies: