From be5a87838ad37a3fca88c7e62f41e11e7d16611b Mon Sep 17 00:00:00 2001 From: Fabio Benedetti Date: Mon, 11 Sep 2023 15:52:17 +0200 Subject: [PATCH] update list design, add head (#361) * update list design, add head * fix back button --- test/next/src/app/globals.css | 8 +- test/next/src/app/layout.tsx | 2 + .../src/app/vercel/blob/api/app/head/route.ts | 11 ++ .../src/app/vercel/blob/app/list/page.tsx | 114 +++++++++++++----- test/next/src/app/vercel/blob/layout.tsx | 4 +- 5 files changed, 103 insertions(+), 36 deletions(-) create mode 100644 test/next/src/app/vercel/blob/api/app/head/route.ts diff --git a/test/next/src/app/globals.css b/test/next/src/app/globals.css index fd81e8858..b1fd10c43 100644 --- a/test/next/src/app/globals.css +++ b/test/next/src/app/globals.css @@ -8,12 +8,8 @@ --background-end-rgb: 255, 255, 255; } -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - } +a { + @apply underline text-blue-600 hover:text-blue-800 visited:text-purple-600; } body { diff --git a/test/next/src/app/layout.tsx b/test/next/src/app/layout.tsx index 32f72c7ed..1b6f461d2 100644 --- a/test/next/src/app/layout.tsx +++ b/test/next/src/app/layout.tsx @@ -1,3 +1,5 @@ +import './globals.css'; + export const metadata = { title: 'Create Next App', description: 'Generated by create next app', diff --git a/test/next/src/app/vercel/blob/api/app/head/route.ts b/test/next/src/app/vercel/blob/api/app/head/route.ts new file mode 100644 index 000000000..7d77dd86d --- /dev/null +++ b/test/next/src/app/vercel/blob/api/app/head/route.ts @@ -0,0 +1,11 @@ +import * as vercelBlob from '@vercel/blob'; +import { NextResponse } from 'next/server'; + +export async function POST(request: Request): Promise { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const body: { url: string } = await request.json(); + if (!body.url) + return NextResponse.json(new Error('url is required'), { status: 400 }); + + return NextResponse.json(await vercelBlob.head(body.url)); +} diff --git a/test/next/src/app/vercel/blob/app/list/page.tsx b/test/next/src/app/vercel/blob/app/list/page.tsx index 2daa0901b..6a819c746 100644 --- a/test/next/src/app/vercel/blob/app/list/page.tsx +++ b/test/next/src/app/vercel/blob/app/list/page.tsx @@ -8,9 +8,14 @@ export default function AppList(): JSX.Element { const [result, setResult] = useState(); const [searchPrefix, setSearchPrefix] = useState(''); const [urlsToRemove, setUrlsToRemove] = useState([]); + const [head, setHead] = useState(); const getList = useCallback( - async (cursor: string, prefix: string = searchPrefix) => { + async ( + cursor: string | null, + prefix: string = searchPrefix, + reset = false + ) => { const search = new URLSearchParams(); search.set('limit', '10'); if (prefix) { @@ -19,9 +24,13 @@ export default function AppList(): JSX.Element { if (cursor) { search.set('cursor', cursor); } + if (reset) { + setResult(undefined); + } const data = (await fetch(`${API_ROOT}/list?${search.toString()}`).then( (r) => r.json() )) as vercelBlob.ListBlobResult; + setResult({ ...data, blobs: cursor ? [...(result?.blobs || []), ...data.blobs] : data.blobs, @@ -48,7 +57,23 @@ export default function AppList(): JSX.Element { 'Content-Type': 'application/json', }, }); - await getList('', searchPrefix); + if (result) { + setResult({ + ...result, + blobs: result.blobs.filter((b) => !urls.includes(b.url)), + }); + } + }; + + const handleHead = async (url: string): Promise => { + const data = (await fetch(`${API_ROOT}/head`, { + method: 'POST', + body: JSON.stringify({ url }), + headers: { + 'Content-Type': 'application/json', + }, + }).then((r) => r.json())) as vercelBlob.HeadBlobResult; + setHead(data); }; if (!result) { @@ -56,31 +81,43 @@ export default function AppList(): JSX.Element { } return ( - <> +

App Router List blob items

- setSearchPrefix(e.target.value)} - placeholder="prefix" - type="text" - value={searchPrefix} - /> - - - -
    +
    + setSearchPrefix(e.target.value)} + placeholder="prefix" + type="text" + value={searchPrefix} + /> + + +
    +
      +
    • +

      Select

      +

      path

      +

      size

      +

      download

      +

      date

      +
    • {result.blobs.map((blob) => ( -
    • +
    • { if (e.target.checked) { setUrlsToRemove([...urlsToRemove, blob.url]); @@ -90,9 +127,26 @@ export default function AppList(): JSX.Element { }} type="checkbox" /> - {blob.pathname} - {blob.size} - - {new Date(blob.uploadedAt).toISOString()} - {blob.url} +

      {blob.pathname}

      +

      {blob.size}

      + + download + +

      {new Date(blob.uploadedAt).toISOString()}

      +
    {result.hasMore && result.cursor ? ( - <> +
    Cursor: {result.cursor}
    - +
    ) : null} - + {head ?
    {JSON.stringify(head)}
    : null} +
); } diff --git a/test/next/src/app/vercel/blob/layout.tsx b/test/next/src/app/vercel/blob/layout.tsx index 61c220882..d3b336545 100644 --- a/test/next/src/app/vercel/blob/layout.tsx +++ b/test/next/src/app/vercel/blob/layout.tsx @@ -7,7 +7,9 @@ export default function Layout({ }): JSX.Element { return (
- ← Home + {children}
);