diff --git a/.forgejo/workflows/build.yaml b/.forgejo/workflows/build.yaml new file mode 100644 index 0000000..1b6ba8f --- /dev/null +++ b/.forgejo/workflows/build.yaml @@ -0,0 +1,16 @@ +on: + workflow_dispatch: + push: + +jobs: + build: + runs-on: docker + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 'latest' + check-latest: true + cache: 'yarn' + - run: | + yarn build diff --git a/astro.config.mjs b/astro.config.mjs index f36ecd5..eceea68 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -59,8 +59,7 @@ export default defineConfig({ '/studio/[slug]': { status: 307, destination: '/maintenance' }, '/studio/list': { status: 307, destination: '/maintenance' }, '/holy12': { status: 307, destination: '/maintenance' }, - '/request': { status: 307, destination: '/maintenance' }, - '/search': { status: 307, destination: '/maintenance' } + '/request': { status: 307, destination: '/maintenance' } }, security: { checkOrigin: false diff --git a/prisma/migrations/20250315025817_add_display_name/migration.sql b/prisma/migrations/20250315025817_add_display_name/migration.sql new file mode 100644 index 0000000..d81b774 --- /dev/null +++ b/prisma/migrations/20250315025817_add_display_name/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `users` ADD COLUMN `displayUsername` VARCHAR(191) NOT NULL DEFAULT 'Default display name'; diff --git a/prisma/migrations/20250315153419_full_index_for_album_search/migration.sql b/prisma/migrations/20250315153419_full_index_for_album_search/migration.sql new file mode 100644 index 0000000..0104251 --- /dev/null +++ b/prisma/migrations/20250315153419_full_index_for_album_search/migration.sql @@ -0,0 +1,2 @@ +-- CreateIndex +CREATE FULLTEXT INDEX `albums_title_subTitle_idx` ON `albums`(`title`, `subTitle`); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index eb3efd6..d6d1f7a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -153,6 +153,8 @@ model albums { relatedAlbums related_album[] @relation("related_album_albumIdToalbums") relatedTo related_album[] @relation("related_album_relatedIdToalbums") stores stores[] + + @@fulltext([title, subTitle]) } model animation { @@ -402,14 +404,15 @@ model submissions { } model users { - id String @id @db.VarChar(255) - name String @db.VarChar(20) - username String @unique @db.VarChar(255) - email String? @unique @db.VarChar(255) - emailVerified Boolean - createdAt DateTime @db.DateTime(0) - updatedAt DateTime @db.DateTime(0) - image String? @db.VarChar(255) + id String @id @db.VarChar(255) + name String @db.VarChar(20) + username String @unique @db.VarChar(255) + displayUsername String @default("Default display name") + email String? @unique @db.VarChar(255) + emailVerified Boolean + createdAt DateTime @db.DateTime(0) + updatedAt DateTime @db.DateTime(0) + image String? @db.VarChar(255) roles User_Role[] histories albumHistories[] diff --git a/src/components/Header.astro b/src/components/Header.astro index f5bf8c5..af839bb 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -11,6 +11,8 @@ import Toggler from './header/Toggler.astro' import NavButton from './header/NavButton.astro' import LoginNav from './header/LoginNav.astro' import prismaClient from 'utils/prisma-client.js' +import { Icon } from 'astro-icon/components' +import SearchBar from './search/SearchBar.astro' const { value: bannerId } = (await prismaClient.config.findUnique({ where: { name: 'banner' } })) ?? {} const { value: bannerPosition } = (await prismaClient.config.findUnique({ where: { name: 'banner-position' } })) ?? {} @@ -42,7 +44,7 @@ const { session } = Astro.locals - + {m.home()} {m.lastaddednav()} @@ -95,6 +97,8 @@ const { session } = Astro.locals > ) : null } + + - + diff --git a/src/components/albumPage/TrackList.tsx b/src/components/albumPage/TrackList.tsx index 8376ae4..972c484 100644 --- a/src/components/albumPage/TrackList.tsx +++ b/src/components/albumPage/TrackList.tsx @@ -33,13 +33,13 @@ export default function TrackList(props: Props) { - + {discs.length > 0 && discs[current].body?.split('\n').map((track, i) => ( - {i + 1} + {(i + 1).toString().padStart(2, '0')}. {track} ))} @@ -50,4 +50,4 @@ export default function TrackList(props: Props) { ) -} +} \ No newline at end of file diff --git a/src/components/header/NavButton.astro b/src/components/header/NavButton.astro index ede444c..f1b2b95 100644 --- a/src/components/header/NavButton.astro +++ b/src/components/header/NavButton.astro @@ -1,8 +1,5 @@ --- -import Button from '../Button' -import clsx from 'clsx' - -const { class: className } = Astro.props +const { class: className, ...rest } = Astro.props --- diff --git a/src/components/header/Toggler.astro b/src/components/header/Toggler.astro index 8c81a6a..fb5a1ce 100644 --- a/src/components/header/Toggler.astro +++ b/src/components/header/Toggler.astro @@ -2,17 +2,11 @@ import { Icon } from 'astro-icon/components' --- - + - + - + diff --git a/src/components/search/AlbumSearch.astro b/src/components/search/AlbumSearch.astro new file mode 100644 index 0000000..6016d99 --- /dev/null +++ b/src/components/search/AlbumSearch.astro @@ -0,0 +1,72 @@ +--- +import type { Prisma } from '@prisma/client' +import type { DefaultArgs } from '@prisma/client/runtime/library' +import { Image } from 'astro:assets' + +import prismaClient from 'utils/prisma-client' + +interface Props { + query: string +} + +const take = 20 +const { query } = Astro.props +const findQuery: Prisma.albumsFindManyArgs = { + select: { title: true, releaseDate: true, id: true }, + where: { + OR: [ + { + title: { + search: query + .toLowerCase() + .split('_') + .map((w) => `+${w}`) + .join(' ') + } + }, + { + subTitle: { + search: query + .toLowerCase() + .split('_') + .map((w) => `+${w}`) + .join(' ') + } + } + ] + }, + orderBy: { publishedAt: 'desc' } +} +const countQuery: Prisma.albumsCountArgs = { + where: findQuery.where +} + +const [count, search] = await Promise.all([ + prismaClient.albums.count(countQuery), + prismaClient.albums.findMany({ ...findQuery, take }) +]) +--- + +Albums ({count}) {count > take ? `/ Showing first ${take} results` : null} + + { + search.map((album) => ( + + + + + + {album.title} + {album.releaseDate?.toISOString().split('T')[0]} + + + )) + } + diff --git a/src/components/search/SearchBar.astro b/src/components/search/SearchBar.astro new file mode 100644 index 0000000..19cf271 --- /dev/null +++ b/src/components/search/SearchBar.astro @@ -0,0 +1,52 @@ +--- +import { Icon } from 'astro-icon/components' +import NavButton from 'components/header/NavButton.astro' +import { getRandom } from 'utils/form' + +const placeholders = ['Tekken', 'Kingdom Hearts', 'The World Ends with You', 'Persona', 'Splatoon'] +const placeholder = getRandom(placeholders) +--- + + + + + + + + + + + + + + diff --git a/src/img/icons/close.svg b/src/img/icons/close.svg new file mode 100644 index 0000000..ee1290f --- /dev/null +++ b/src/img/icons/close.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/img/icons/search.svg b/src/img/icons/search.svg new file mode 100644 index 0000000..a0a56c5 --- /dev/null +++ b/src/img/icons/search.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/pages/album/[id].astro b/src/pages/album/[id].astro index 1183bf9..2feb2eb 100644 --- a/src/pages/album/[id].astro +++ b/src/pages/album/[id].astro @@ -73,10 +73,10 @@ const { currentLocale } = Astro @@ -102,18 +102,20 @@ const { currentLocale } = Astro { (album?.artists.length ?? 0) > 0 && ( - {m.artists()} + {m.artists()} {album?.artists.map(({ artist }) => artist.name).join(', ')} ) } - {m.classification()} + {m.classification()} { [ - album?.categories.map(({ categoryName }) => (m as any)[`${categoryName}Osts`]()).join(' & '), + album?.categories + .map(({ categoryName }) => m[`${categoryName}Osts` as keyof typeof m]()) + .join(' & '), album?.classifications.map(({ classificationName }) => classificationName).join(', ') ] .filter((f) => f !== '') @@ -124,7 +126,7 @@ const { currentLocale } = Astro { album?.label && ( - {m.publishedBy()} + {m.publishedBy()} {album?.label} @@ -136,7 +138,7 @@ const { currentLocale } = Astro { (album?.platforms.length ?? 0) > 0 && ( - {m.platforms()} + {m.platforms()} {album?.platforms.map(({ platform }, i) => ( @@ -159,7 +161,7 @@ const { currentLocale } = Astro { (album?.games.length ?? 0) > 0 && ( - {m.games()} + {m.games()} {album?.games.map(({ game }, i) => ( @@ -176,7 +178,7 @@ const { currentLocale } = Astro { (album?.animations.length ?? 0) > 0 && ( - {m.animations()} + {m.animations()} {album?.animations.map(({ animation }, i) => ( @@ -192,13 +194,23 @@ const { currentLocale } = Astro } - {m.avgRating()} + {m.avgRating()} + { + album?.vgmdb && ( + + {m.checkVGMDB()}: + + + + + ) + } diff --git a/src/pages/index.astro b/src/pages/index.astro index 3e31235..1d4eda7 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -27,7 +27,7 @@ const lastAlbums = await prismaClient.albums.findMany({ {m.recentReleases()} - + { recentAlbums.map((album) => ( @@ -42,7 +42,7 @@ const lastAlbums = await prismaClient.albums.findMany({ {m.lastAdded()} - + { lastAlbums.map((album) => ( diff --git a/src/pages/last-added/[...page].astro b/src/pages/last-added/[...page].astro index 7a1ac55..61c02da 100644 --- a/src/pages/last-added/[...page].astro +++ b/src/pages/last-added/[...page].astro @@ -39,7 +39,7 @@ const listProps = { fullPageList, page } {m.lastAdded()} - + { lastAlbums.map((album) => ( diff --git a/src/pages/search.astro b/src/pages/search.astro new file mode 100644 index 0000000..f90c507 --- /dev/null +++ b/src/pages/search.astro @@ -0,0 +1,18 @@ +--- +import AlbumSearch from 'components/search/AlbumSearch.astro' +import BaseLayout from 'layouts/base.astro' + +const query = Astro.url.searchParams.get('q') +if (!query) return Astro.redirect(404) +--- + + + + + Search results for: {query} + + + + + + diff --git a/src/utils/form.ts b/src/utils/form.ts index bf8042f..2ae18b4 100644 --- a/src/utils/form.ts +++ b/src/utils/form.ts @@ -21,3 +21,8 @@ export async function parseForm(request: Request) { const data = JSON.parse(dataInput) return { ...data, ...rest } } + +export function getRandom(array: T[]): T { + const randomIndex = Math.floor(Math.random() * array.length) + return array[randomIndex] +}