Skip to content

Commit 0571ff2

Browse files
refactor: replace Page component with PageLayout in MetadataManagerPage and update CHANGELOG for component name change
1 parent 87cdea7 commit 0571ff2

File tree

4 files changed

+112
-39
lines changed

4 files changed

+112
-39
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3030
### Added
3131

3232
- **Metadata Manager page** at `/audio-metadata-manager`: file picker to choose an audio file, POST to `NEXT_PUBLIC_API_BASE_URL/audio/metadata/full/`, display full metadata in six sections (Technical information, Unified metadata, By metadata format, Format priorities, Formats headers, Metadata raw). Inline loading and error display; no popup. Includes unit tests.
33-
- **Project setup**: Cursor rules (style, Tailwind, testing, SemVer, versioning, commit format, PR workflow), docs (STYLE_GUIDE, SEMANTIC_HTML, DATA_ATTRIBUTES, testing, SEMVER_GUIDE, VERSIONING), GitHub workflows (validate, branch-protection, publish), CONTRIBUTING.md, README, PR template, `.gitignore`. Vitest + Testing Library for tests. Reusable `Page` component and `useGetFullMetadata` hook with Zod schema for response validation.
33+
- **Project setup**: Cursor rules (style, Tailwind, testing, SemVer, versioning, commit format, PR workflow), docs (STYLE_GUIDE, SEMANTIC_HTML, DATA_ATTRIBUTES, testing, SEMVER_GUIDE, VERSIONING), GitHub workflows (validate, branch-protection, publish), CONTRIBUTING.md, README, PR template, `.gitignore`. Vitest + Testing Library for tests. Reusable `PageLayout` component and `useGetFullMetadata` hook with Zod schema for response validation.
3434

3535
[Unreleased]: https://github.com/your-org/audiometa-frontend/compare/v0.1.0...HEAD
3636
[0.1.0]: https://github.com/your-org/audiometa-frontend/releases/tag/v0.1.0

app/audio-metadata-manager/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22

33
import { useRef, useState } from "react";
4-
import Page from "@/components/Page";
4+
import PageLayout from "@/components/PageLayout";
55
import { useGetFullMetadata } from "@/hooks/useGetFullMetadata";
66
import type { AudioMetadataDetailed } from "@/schemas/audio-metadata";
77

@@ -30,7 +30,7 @@ export default function MetadataManagerPage() {
3030
}
3131

3232
return (
33-
<Page title="Audio Metadata Manager" dataPage="audio-metadata-manager">
33+
<PageLayout title="Audio Metadata Manager" dataPage="audio-metadata-manager">
3434
<div className="flex flex-col gap-6">
3535
<div className="flex flex-wrap items-center gap-3 rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
3636
<input
@@ -163,6 +163,6 @@ export default function MetadataManagerPage() {
163163
</section>
164164
</div>
165165
</div>
166-
</Page>
166+
</PageLayout>
167167
);
168168
}

components/Page.tsx

Lines changed: 0 additions & 35 deletions
This file was deleted.

components/PageLayout.tsx

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import Image from "next/image";
2+
import { ReactNode } from "react";
3+
4+
function LinkedInIcon() {
5+
return (
6+
<svg className="h-5 w-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden>
7+
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
8+
</svg>
9+
);
10+
}
11+
12+
function MastodonIcon() {
13+
return (
14+
// eslint-disable-next-line @next/next/no-img-element
15+
<img
16+
src="/icons/mastodon.svg"
17+
alt=""
18+
width={20}
19+
height={20}
20+
className="h-5 w-5 shrink-0"
21+
aria-hidden
22+
/>
23+
);
24+
}
25+
26+
function MailIcon() {
27+
return (
28+
<svg className="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
29+
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" />
30+
<polyline points="22,6 12,13 2,6" />
31+
</svg>
32+
);
33+
}
34+
35+
interface PageLayoutProps {
36+
title: string;
37+
children: ReactNode;
38+
/** Route or feature id for E2E/analytics (e.g. "audio-metadata-manager"). See docs/DATA_ATTRIBUTES.md. */
39+
dataPage: string;
40+
}
41+
42+
export default function PageLayout({ title, children, dataPage }: PageLayoutProps) {
43+
return (
44+
<div
45+
className="flex min-h-screen min-w-0 flex-1 flex-col bg-gradient-to-b from-slate-50 to-slate-100"
46+
data-page={dataPage}
47+
>
48+
<header className="flex-none border-b border-slate-200 bg-white/80 px-6 py-5 backdrop-blur-sm">
49+
<h1 className="text-2xl font-semibold tracking-tight text-slate-800">
50+
{title}
51+
</h1>
52+
</header>
53+
<div className="min-h-0 flex-1 overflow-y-auto px-6 py-6">{children}</div>
54+
<footer className="flex flex-none flex-wrap items-center justify-center gap-x-4 gap-y-1 border-t border-slate-200 bg-white/60 px-6 py-4 backdrop-blur-sm">
55+
<span className="flex items-center gap-2 text-sm text-slate-500">
56+
Powered by
57+
<Image
58+
src="/logo-round.png"
59+
alt="Audiometa"
60+
width={28}
61+
height={28}
62+
className="h-7 w-7"
63+
/>
64+
</span>
65+
{process.env.NEXT_PUBLIC_SITE_DEVELOPER && (
66+
<span className="flex items-center gap-2 text-sm text-slate-500">
67+
Developer:{" "}
68+
<a
69+
href={process.env.NEXT_PUBLIC_SITE_DEVELOPER_GITHUB_URL}
70+
target="_blank"
71+
rel="noopener noreferrer"
72+
className="font-medium text-slate-700 underline decoration-slate-400 underline-offset-2 hover:text-slate-900 hover:decoration-slate-600"
73+
>
74+
{process.env.NEXT_PUBLIC_SITE_DEVELOPER}
75+
</a>
76+
<span className="flex items-center gap-1" aria-hidden="true">
77+
<a
78+
href={process.env.NEXT_PUBLIC_SITE_DEVELOPER_LINKEDIN_URL}
79+
target="_blank"
80+
rel="noopener noreferrer"
81+
className="rounded p-0.5 text-slate-500 transition-colors hover:text-slate-800"
82+
aria-label="Developer on LinkedIn"
83+
>
84+
<LinkedInIcon />
85+
</a>
86+
<a
87+
href={process.env.NEXT_PUBLIC_SITE_DEVELOPER_MASTODON_URL}
88+
target="_blank"
89+
rel="me noopener noreferrer"
90+
className="rounded p-0.5 text-slate-500 transition-colors hover:text-slate-800"
91+
aria-label="Developer on Mastodon"
92+
>
93+
<MastodonIcon />
94+
</a>
95+
<a
96+
href={`mailto:${process.env.NEXT_PUBLIC_SITE_DEVELOPER_EMAIL}`}
97+
className="rounded p-0.5 text-slate-500 transition-colors hover:text-slate-800"
98+
aria-label="Email developer"
99+
>
100+
<MailIcon />
101+
</a>
102+
</span>
103+
</span>
104+
)}
105+
</footer>
106+
</div>
107+
);
108+
}

0 commit comments

Comments
 (0)