Skip to content

Commit

Permalink
Merge pull request #24 from sjdonado/search-card-redesign
Browse files Browse the repository at this point in the history
Search card redesign
  • Loading branch information
sjdonado authored Jul 22, 2024
2 parents a7ad3fc + 165eb41 commit 5abfe6b
Show file tree
Hide file tree
Showing 24 changed files with 473 additions and 247 deletions.
Binary file modified bun.lockb
Binary file not shown.
5 changes: 5 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[test]
coverage = true

[define]
"process.env.NODE_ENV" = "'test'"
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
"dev": "concurrently \"bun run build:dev\" \"bun run --watch www/bin.ts\"",
"build:dev": "vite build --mode=development --watch",
"build": "vite build",
"test": "DATABASE_PATH=:memory: bun test --coverage"
"test": "bun test"
},
"dependencies": {
"@elysiajs/html": "^1.0.2",
"@elysiajs/static": "^1.0.2",
"@hotwired/stimulus": "^3.2.2",
"axios": "^1.6.8",
"axios-retry": "^4.4.1",
"cache-manager": "~4.1.0",
"cache-manager-sqlite": "^0.2.0",
"cache-manager": "^5.7.3",
"cache-manager-bun-sqlite3": "^0.1.0",
"cheerio": "^1.0.0-rc.12",
"elysia": "^1.0.14",
"howler": "^2.2.4",
"notyf": "^3.10.0",
"pino": "^8.20.0",
"pino-pretty": "^11.0.0",
"puppeteer": "^22.7.0",
Expand All @@ -38,6 +41,7 @@
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"rollup-plugin-copy": "^3.5.0",
"stimulus-vite-helpers": "^3.1.0",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5",
"vite": "^5.2.10"
Expand Down
36 changes: 36 additions & 0 deletions public/assets/app.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion public/assets/entry.js

This file was deleted.

2 changes: 1 addition & 1 deletion src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const ENV = {
version: version,
},
cache: {
databasePath: Bun.env.DATABASE_PATH!,
databasePath: Bun.env.DATABASE_PATH ?? ':memory:',
expTime: 60 * 60 * 24 * 7, // 1 week in seconds
},
};
3 changes: 2 additions & 1 deletion src/routes/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const pageRouter = new Elysia()
return <ErrorMessage message={error.message} />;
}

return <ErrorMessage message="Something went wrong, try again later." />;
return <ErrorMessage message="Something went wrong, please try again later." />;
})
.get(
'/',
Expand Down Expand Up @@ -62,6 +62,7 @@ export const pageRouter = new Elysia()
'/search',
async ({ body: { link } }) => {
const searchResult = await search({ link });

return <SearchCard searchResult={searchResult} />;
},
{
Expand Down
25 changes: 9 additions & 16 deletions src/services/cache.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
const sqliteStore = require('cache-manager-sqlite');
const cacheManager = require('cache-manager');
import { caching } from 'cache-manager';
import bunSqliteStore from 'cache-manager-bun-sqlite3';

import { ENV } from '~/config/env';
import { SearchMetadata, SearchResultLink } from './search';

export const cacheStore = cacheManager.caching({
store: sqliteStore,
export const cacheStore = await caching(bunSqliteStore, {
name: 'cache',
path: ENV.cache.databasePath,
ttl: ENV.cache.expTime,
serializer: 'json',
});

export const cacheSearchResultLink = async (
url: URL,
searchResultLink: SearchResultLink
) => {
await cacheStore.set(`search:${url.toString()}`, searchResultLink, {
ttl: ENV.cache.expTime,
});
await cacheStore.set(`search:${url.toString()}`, searchResultLink);
};

export const getCachedSearchResultLink = async (url: URL) => {
Expand All @@ -26,9 +25,7 @@ export const getCachedSearchResultLink = async (url: URL) => {
};

export const cacheSearchMetadata = async (id: string, searchMetadata: SearchMetadata) => {
await cacheStore.set(`metadata:${id}`, searchMetadata, {
ttl: ENV.cache.expTime,
});
await cacheStore.set(`metadata:${id}`, searchMetadata);
};

export const getCachedSearchMetadata = async (id: string) => {
Expand All @@ -38,19 +35,15 @@ export const getCachedSearchMetadata = async (id: string) => {
};

export const cacheSpotifyAccessToken = async (accessToken: string, expTime: number) => {
await cacheStore.set('spotify:accessToken', accessToken, {
ttl: expTime,
});
await cacheStore.set('spotify:accessToken', accessToken, expTime);
};

export const getCachedSpotifyAccessToken = async () => {
return cacheStore.get('spotify:accessToken');
};

export const cacheShortenLink = async (link: string, refer: string) => {
await cacheStore.set(`url-shortener:${link}`, refer, {
ttl: ENV.cache.expTime,
});
await cacheStore.set(`url-shortener:${link}`, refer);
};

export const getCachedShortenLink = async (link: string) => {
Expand Down
20 changes: 16 additions & 4 deletions src/services/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,12 @@ export const search = async ({
url: link,
isVerified: true,
},
],
] as SearchResultLink[],
};
}

const searchResultsPromise = Promise.all([
searchAdapters.includes(Adapter.Spotify) && searchParser.type !== Adapter.Spotify
? getSpotifyLink(query, metadata)
: null,
searchParser.type !== Adapter.Spotify ? getSpotifyLink(query, metadata) : null,
searchAdapters.includes(Adapter.YouTube) && searchParser.type !== Adapter.YouTube
? getYouTubeLink(query, metadata)
: null,
Expand All @@ -128,6 +126,20 @@ export const search = async ({
shortenLink(`${ENV.app.url}?id=${id}`),
]);

if (searchParser.type !== Adapter.Spotify) {
const spotifySearchResult = searchResults.find(
searchResult => searchResult?.type === Adapter.Spotify
);

if (spotifySearchResult) {
const spotifySearchParser = await getSearchParser(spotifySearchResult.url);
metadata = await getSpotifyMetadata(
spotifySearchParser.id,
spotifySearchResult.url
);
}
}

const links = searchResults.filter(Boolean);

logger.info(`[${search.name}] (results) ${JSON.stringify(links, null, 2)}`);
Expand Down
32 changes: 0 additions & 32 deletions src/views/components/search-bar.tsx

This file was deleted.

125 changes: 102 additions & 23 deletions src/views/components/search-card.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,122 @@
import { Adapter } from '~/config/enum';
import { SearchResult } from '~/services/search';

import SearchLink from './search-link';
const SEARCH_LINK_DICT = {
[Adapter.Spotify]: {
icon: 'fab fa-spotify',
label: 'Listen on Spotify',
},
[Adapter.YouTube]: {
icon: 'fab fa-youtube',
label: 'Listen on YouTube Music',
},
[Adapter.Deezer]: {
icon: 'fab fa-deezer',
label: 'Listen on Deezer',
},
[Adapter.AppleMusic]: {
icon: 'fab fa-apple',
label: 'Listen on Apple Music',
},
[Adapter.Tidal]: {
icon: 'fa fa-music',
label: 'Listen on Tidal',
},
[Adapter.SoundCloud]: {
icon: 'fab fa-soundcloud',
label: 'Listen on SoundCloud',
},
};

export default function SearchCard(props: { searchResult: SearchResult }) {
return (
<div
id="search-card"
data-id={props.searchResult.id}
class="relative m-4 flex max-w-2xl flex-wrap items-start justify-center rounded-lg border border-white md:p-4"
data-controller="search-card"
data-search-card-id-value={props.searchResult.id}
data-search-card-universal-link-value={props.searchResult.universalLink}
data-search-card-audio-value={props.searchResult.audio}
class="relative m-4 flex max-w-3xl flex-wrap items-start justify-center gap-4 rounded-lg shadow-lg md:p-4"
>
<button
type="button"
class="absolute right-2 top-2 p-1 text-white"
onclick={`shareLink('${props.searchResult.universalLink}')`}
>
<i class="fas fa-up-right-from-square" />
</button>
<div class="m-4 w-full md:w-44">
<div class="flex w-full items-center justify-start gap-4">
<img
class="mx-auto w-28 md:w-44"
class="w-24 max-w-24 rounded-lg md:w-28"
src={props.searchResult.image}
alt={props.searchResult.title}
/>
</div>
<div class="mb-2 flex-1 flex-col items-start p-2 md:mr-6">
<div class="mb-2 hyphens-auto text-center text-2xl font-normal md:text-start">
{props.searchResult.title}
<div class="flex flex-col gap-1">
<h3 class="hyphens-auto text-lg font-normal md:text-start md:text-2xl">
{props.searchResult.title}
</h3>
<p class="text-sm text-zinc-400">{props.searchResult.description}</p>
<div class="mt-2 flex gap-2">
<button
data-action="search-card#toggleAudio"
type="button"
class="relative flex items-center justify-center gap-2 rounded-lg bg-zinc-700 px-3 py-1 text-sm font-semibold"
>
<i data-search-card-target="icon" class="fas fa-play w-3" />
Audio Preview
<div className="absolute bottom-0 left-0 mx-[0.3rem] my-[0.01rem] h-[0.15rem] w-[93%] rounded-lg bg-zinc-600">
<div
data-search-card-target="audioProgress"
class="h-full rounded-lg bg-white"
style={{ width: '0%' }}
></div>
</div>
</button>
<button
data-action="search-card#share"
type="button"
class="flex items-center justify-center gap-2 rounded-lg bg-zinc-700 px-3 py-1 text-sm font-semibold"
>
<i class="fas fa-arrow-up-from-bracket" />
Share
</button>
</div>
</div>
<p class="text-center text-sm md:text-start">{props.searchResult.description}</p>
</div>
<div class="mt-2 flex min-h-12 flex-1 flex-col items-start p-2">
{props.searchResult.links.length === 0 && (
<p class="mt-6 w-full text-center text-sm md:text-start">
<p class="w-full text-center text-sm md:text-start">
Not available on other platforms
</p>
)}
{props.searchResult.links.length > 0 && (
<ul class="mt-4 min-w-48 text-base">
{props.searchResult.links.map(({ type, url, isVerified }) => (
<SearchLink type={type} url={url} isVerified={isVerified} />
))}
<ul class="w-full">
{props.searchResult.links.map(({ type, url, isVerified }) => {
const searchResult = SEARCH_LINK_DICT[type];
return (
<li
data-controller="search-link"
data-search-link-url-value={url}
class="flex items-center justify-between gap-1 rounded-lg p-2 hover:bg-zinc-700"
>
<a
href={url}
target="_blank"
rel="noreferrer"
aria-label={searchResult.label}
class="flex items-center"
>
<i class={`${searchResult.icon} w-8`} />
<p class="underline decoration-0 underline-offset-2">
{searchResult.label}
</p>
{isVerified && (
<span
class="ml-1 inline-flex items-center justify-center rounded-full bg-green-500 p-1 text-[0.56rem]"
aria-label="Verified"
>
<i class="fas fa-check" />
</span>
)}
</a>
<button type="button" data-action="search-link#share">
<i class="fa fa-regular fa-copy px-2" />
</button>
</li>
);
})}
</ul>
)}
</div>
Expand Down
Loading

0 comments on commit 5abfe6b

Please sign in to comment.