update: header

This commit is contained in:
alikia2x (寒寒) 2025-07-06 19:06:32 +08:00
parent b2488bddfe
commit a660514ade
Signed by: alikia2x
GPG Key ID: 56209E0CCD8420C6
13 changed files with 201 additions and 126 deletions

View File

@ -9,3 +9,5 @@ MiSans.css
*.yaml *.yaml
*.yml *.yml
*.mdx *.mdx
packages/solid/src/drizzle/cred
packages/solid/src/drizzle/main

View File

@ -95,7 +95,7 @@
"packages/solid": { "packages/solid": {
"name": "example-basic", "name": "example-basic",
"dependencies": { "dependencies": {
"@m3-components/solid": "^0.0.3", "@m3-components/solid": "0.0.7",
"@solidjs/meta": "^0.29.4", "@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.0", "@solidjs/router": "^0.15.0",
"@solidjs/start": "^1.1.0", "@solidjs/start": "^1.1.0",
@ -346,7 +346,7 @@
"@koshnic/ratelimit": ["@koshnic/ratelimit@1.0.3", "", { "dependencies": { "@types/chai": "^4.3.9", "@types/mocha": "^10.0.3", "chai": "^4.3.10", "ioredis": "^5.3.2", "mocha": "^10.2.0" } }, "sha512-cfDcSc+I+M4hNM+/4M+lfn8UuTq4OEFKl78ThOcGNaO7g8tWb1vm2qVpV1p1loYao1mqk00NBNwHQu2E/qFq2g=="], "@koshnic/ratelimit": ["@koshnic/ratelimit@1.0.3", "", { "dependencies": { "@types/chai": "^4.3.9", "@types/mocha": "^10.0.3", "chai": "^4.3.10", "ioredis": "^5.3.2", "mocha": "^10.2.0" } }, "sha512-cfDcSc+I+M4hNM+/4M+lfn8UuTq4OEFKl78ThOcGNaO7g8tWb1vm2qVpV1p1loYao1mqk00NBNwHQu2E/qFq2g=="],
"@m3-components/solid": ["@m3-components/solid@0.0.3", "", { "dependencies": { "solid-js": "^1.9.5" } }, "sha512-3TjrTTQyiD41uXO7TPuV6Q0FaemsBik4FXg4/2wi858hIkzre3rh/rmHNYG90z73/U9K0kTB6zZgO3HpnhVEwg=="], "@m3-components/solid": ["@m3-components/solid@0.0.7", "", { "dependencies": { "solid-js": "^1.9.5" } }, "sha512-pyu8Of2wys0pgAV08lz9aOGGkiQPjzCXfuQyJeTu0auKYe8EvmqlcgH3JbX0cRP4CVxp6yd9ppfQT9B/i9DgvQ=="],
"@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@2.0.0", "", { "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg=="], "@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@2.0.0", "", { "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg=="],

View File

@ -8,7 +8,7 @@
"version": "vinxi version" "version": "vinxi version"
}, },
"dependencies": { "dependencies": {
"@m3-components/solid": "^0.0.3", "@m3-components/solid": "0.0.7",
"@solidjs/meta": "^0.29.4", "@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.0", "@solidjs/router": "^0.15.0",
"@solidjs/start": "^1.1.0", "@solidjs/start": "^1.1.0",

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,9 @@
import { type SVGIconComponent } from "./types";
export const MenuOpen: SVGIconComponent = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M4 18q-.425 0-.712-.288T3 17t.288-.712T4 16h11q.425 0 .713.288T16 17t-.288.713T15 18zm14.9-1.7l-3.6-3.6q-.3-.3-.3-.7t.3-.7l3.6-3.6q.275-.275.7-.275t.7.275t.275.7t-.275.7L17.4 12l2.9 2.9q.275.275.275.7t-.275.7t-.7.275t-.7-.275M4 13q-.425 0-.712-.288T3 12t.288-.712T4 11h8q.425 0 .713.288T13 12t-.288.713T12 13zm0-5q-.425 0-.712-.288T3 7t.288-.712T4 6h11q.425 0 .713.288T16 7t-.288.713T15 8z" />
</svg>
);
}

View File

@ -0,0 +1,3 @@
import { Component, JSX } from "solid-js";
type SVGIconComponent = Component<JSX.SvgSVGAttributes<SVGElement>>;

View File

@ -1,5 +1,31 @@
import { Component } from "solid-js"; import { Component } from "solid-js";
import {
AppBar,
AppBarSearchBox,
IconButton,
LeadingElement,
TrailingElementGroup,
TrailingElement
} from "@m3-components/solid";
import "@m3-components/solid/index.css";
import { MenuOpen } from "~/components/icons/MenuOpen";
export const Header: Component = () => { export const Header: Component = () => {
return <img src="/icons/TitleBar Mobile Light.svg" alt="logo" />; return (
<div class="mt-4 top-0 left-0 w-full">
<AppBar variant="search">
<LeadingElement>
<IconButton>
<MenuOpen/>
</IconButton>
</LeadingElement>
<AppBarSearchBox class="text-center placeholder:text-on-surface-variant text-on-surface" placeholder="搜索" />
<TrailingElementGroup>
<TrailingElement>
<IconButton></IconButton>
</TrailingElement>
</TrailingElementGroup>
</AppBar>
</div>
);
}; };

View File

@ -1,11 +1,14 @@
// @refresh reload // @refresh reload
import { mount, StartClient } from "@solidjs/start/client"; import { mount, StartClient } from "@solidjs/start/client";
import { RequestContextProvider } from "./components/requestContext"; import { RequestContextProvider } from "./components/requestContext";
import { MetaProvider } from "@solidjs/meta";
mount( mount(
() => ( () => (
<RequestContextProvider> <RequestContextProvider>
<MetaProvider>
<StartClient /> <StartClient />
</MetaProvider>
</RequestContextProvider> </RequestContextProvider>
), ),
document.getElementById("app")! document.getElementById("app")!

View File

@ -5,6 +5,7 @@ import { RequestContextProvider } from "~/components/requestContext";
export default createHandler(() => ( export default createHandler(() => (
<RequestContextProvider> <RequestContextProvider>
<MetaProvider>
<StartServer <StartServer
document={({ assets, children, scripts }) => ( document={({ assets, children, scripts }) => (
<html lang="en"> <html lang="en">
@ -12,8 +13,6 @@ export default createHandler(() => (
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
{/*<link rel="icon" href="/favicon.ico" />*/} {/*<link rel="icon" href="/favicon.ico" />*/}
<MetaProvider></MetaProvider>
<title>V档案馆</title>
{assets} {assets}
</head> </head>
<body> <body>
@ -23,5 +22,6 @@ export default createHandler(() => (
</html> </html>
)} )}
/> />
</MetaProvider>
</RequestContextProvider> </RequestContextProvider>
)); ));

View File

@ -1,7 +1,6 @@
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import { useParams } from "@solidjs/router"; import { useParams } from "@solidjs/router";
import { createResource } from "solid-js"; import { createResource } from "solid-js";
import { Title } from "@solidjs/meta";
import { Suspense } from "solid-js"; import { Suspense } from "solid-js";
import { For } from "solid-js"; import { For } from "solid-js";
import { useCachedFetch } from "~/lib/dbCache"; import { useCachedFetch } from "~/lib/dbCache";
@ -10,25 +9,44 @@ import { bilibiliMetadata, videoSnapshot } from "~db/main/schema";
import { desc, eq } from "drizzle-orm"; import { desc, eq } from "drizzle-orm";
import { BilibiliMetadataType, VideoSnapshotType } from "~db/outerSchema"; import { BilibiliMetadataType, VideoSnapshotType } from "~db/outerSchema";
import { Context, useRequestContext } from "~/components/requestContext"; import { Context, useRequestContext } from "~/components/requestContext";
import { Header } from "~/components/shell/Header";
async function getAllSnapshots(aid: number, context: Context) { async function getAllSnapshots(aid: number, context: Context) {
"use server"; "use server";
return useCachedFetch(async () => { return useCachedFetch(
return dbMain.select().from(videoSnapshot).where(eq(videoSnapshot.aid,aid)).orderBy(desc(videoSnapshot.createdAt)); async () => {
}, "all-snapshots", context, [aid]); return dbMain
.select()
.from(videoSnapshot)
.where(eq(videoSnapshot.aid, aid))
.orderBy(desc(videoSnapshot.createdAt));
},
"all-snapshots",
context,
[aid]
);
} }
async function getVideoMetadata(avORbv: number | string, context: Context) { async function getVideoMetadata(avORbv: number | string, context: Context) {
"use server"; "use server";
if (typeof avORbv === "number") { if (typeof avORbv === "number") {
return useCachedFetch(async () => { return useCachedFetch(
async () => {
return dbMain.select().from(bilibiliMetadata).where(eq(bilibiliMetadata.aid, avORbv)).limit(1); return dbMain.select().from(bilibiliMetadata).where(eq(bilibiliMetadata.aid, avORbv)).limit(1);
}, "bili-metadata", context, [avORbv]); },
} "bili-metadata",
else { context,
return useCachedFetch(async () => { [avORbv]
);
} else {
return useCachedFetch(
async () => {
return dbMain.select().from(bilibiliMetadata).where(eq(bilibiliMetadata.bvid, avORbv)).limit(1); return dbMain.select().from(bilibiliMetadata).where(eq(bilibiliMetadata.bvid, avORbv)).limit(1);
}, "bili-metadata", context, [avORbv]); },
"bili-metadata",
context,
[avORbv]
);
} }
} }
@ -78,11 +96,16 @@ export default function VideoInfoPage() {
t: title t: title
}; };
}); });
return ( return (
<>
<Header />
<main class="flex flex-col items-center min-h-screen gap-8 mt-10 md:mt-6 relative z-0 overflow-x-auto pb-8"> <main class="flex flex-col items-center min-h-screen gap-8 mt-10 md:mt-6 relative z-0 overflow-x-auto pb-8">
<div class="w-full lg:max-w-4xl lg:mx-auto lg:p-6"> <div class="w-full lg:max-w-4xl lg:mx-auto lg:p-6">
<Suspense fallback={<div>loading</div>}> <Suspense fallback={<div>loading</div>}>
<Title>{data()?.t}</Title> <title>{data()?.t}</title>
<span>{data()?.t}</span>
<h1 class="text-2xl font-medium ml-2 mb-4"> <h1 class="text-2xl font-medium ml-2 mb-4">
:{" "} :{" "}
<a href={`https://www.bilibili.com/video/av${data()?.v.aid}`} class="underline"> <a href={`https://www.bilibili.com/video/av${data()?.v.aid}`} class="underline">
@ -106,9 +129,9 @@ export default function VideoInfoPage() {
title="发布时间" title="发布时间"
desc={ desc={
data()?.v.publishedAt data()?.v.publishedAt
? DateTime.fromJSDate(new Date(data()?.v.publishedAt || "")).toFormat( ? DateTime.fromJSDate(
"yyyy-MM-dd HH:mm:ss" new Date(data()?.v.publishedAt || "")
) ).toFormat("yyyy-MM-dd HH:mm:ss")
: null : null
} }
/> />
@ -151,13 +174,21 @@ export default function VideoInfoPage() {
"yyyy-MM-dd HH:mm:ss" "yyyy-MM-dd HH:mm:ss"
)} )}
</td> </td>
<td class="border dark:border-zinc-500 px-4 py-2">{snapshot.views}</td> <td class="border dark:border-zinc-500 px-4 py-2">
<td class="border dark:border-zinc-500 px-4 py-2">{snapshot.coins}</td> {snapshot.views}
<td class="border dark:border-zinc-500 px-4 py-2">{snapshot.likes}</td> </td>
<td class="border dark:border-zinc-500 px-4 py-2">
{snapshot.coins}
</td>
<td class="border dark:border-zinc-500 px-4 py-2">
{snapshot.likes}
</td>
<td class="border dark:border-zinc-500 px-4 py-2"> <td class="border dark:border-zinc-500 px-4 py-2">
{snapshot.favorites} {snapshot.favorites}
</td> </td>
<td class="border dark:border-zinc-500 px-4 py-2">{snapshot.shares}</td> <td class="border dark:border-zinc-500 px-4 py-2">
{snapshot.shares}
</td>
<td class="border dark:border-zinc-500 px-4 py-2"> <td class="border dark:border-zinc-500 px-4 py-2">
{snapshot.danmakus} {snapshot.danmakus}
</td> </td>
@ -174,5 +205,6 @@ export default function VideoInfoPage() {
</Suspense> </Suspense>
</div> </div>
</main> </main>
</>
); );
} }