ref: structure of the layout components
add: some links in the left column and a FAB on the top of the right column (desktop view)
This commit is contained in:
parent
1959046184
commit
493cf287f1
@ -4,7 +4,7 @@
|
||||
"": {
|
||||
"name": "example-basic",
|
||||
"dependencies": {
|
||||
"@m3-components/solid": "0.1.17",
|
||||
"@m3-components/solid": "0.2.0",
|
||||
"@solid-primitives/media": "^2.3.3",
|
||||
"@solidjs/meta": "^0.29.4",
|
||||
"@solidjs/router": "^0.15.3",
|
||||
@ -184,7 +184,7 @@
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||
|
||||
"@m3-components/solid": ["@m3-components/solid@0.1.17", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "animejs": "^4.0.2", "solid-js": "^1.9.5", "tailwind-variants": "^1.0.0" } }, "sha512-KXNovjVIl0Tr0WhASn71t07DFO98S2VyDMa0453Q6Z4CA8FA91h65uaGkMxL4r9SmUdMOraxMeKNG8GJgV/bZQ=="],
|
||||
"@m3-components/solid": ["@m3-components/solid@0.2.0", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "animejs": "^4.0.2", "solid-js": "^1.9.5", "tailwind-variants": "^1.0.0" } }, "sha512-kJ2dPUeJlMJFVAUBBkeAbDkVt409LD0aT+hkilnUT5en6IfQCE4EUzk9BPPbYfzMa4B8nutMlfAyRwcYREbJ9A=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
"version": "vinxi version"
|
||||
},
|
||||
"dependencies": {
|
||||
"@m3-components/solid": "0.1.17",
|
||||
"@m3-components/solid": "0.2.0",
|
||||
"@solid-primitives/media": "^2.3.3",
|
||||
"@solidjs/meta": "^0.29.4",
|
||||
"@solidjs/router": "^0.15.3",
|
||||
|
||||
@ -4,7 +4,7 @@ import { FileRoutes } from "@solidjs/start/router";
|
||||
import { onMount, Suspense } from "solid-js";
|
||||
import "./app.css";
|
||||
import "@m3-components/solid/index.css";
|
||||
import { setActiveTab, tabMap } from "./components/shell/Navigation";
|
||||
import { setActiveTab, tabMap } from "./components/layout/Navigation";
|
||||
import { minimatch } from "minimatch";
|
||||
|
||||
export const refreshTab = (path: string) => {
|
||||
|
||||
3
packages/solid/src/components/common.d.ts
vendored
3
packages/solid/src/components/common.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import { JSX } from "solid-js";
|
||||
|
||||
export type DivProps = JSX.HTMLAttributes<HTMLDivElement>
|
||||
export type DivProps = JSX.HTMLAttributes<HTMLDivElement>;
|
||||
export type ElementProps = JSX.HTMLAttributes<HTMLElement>;
|
||||
|
||||
12
packages/solid/src/components/icons/Edit.tsx
Normal file
12
packages/solid/src/components/icons/Edit.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { SVGIconComponent } from "./types";
|
||||
|
||||
export const EditIcon: SVGIconComponent = (props) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" {...props}>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-2 2v-4.25L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.438.65T21 6.4q0 .4-.137.763t-.438.662L7.25 21zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
5
packages/solid/src/components/icons/index.tsx
Normal file
5
packages/solid/src/components/icons/index.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
export * from "./Home";
|
||||
export * from "./Music";
|
||||
export * from "./Album";
|
||||
export * from "./Search";
|
||||
export * from "./Edit";
|
||||
10
packages/solid/src/components/layout/Body.tsx
Normal file
10
packages/solid/src/components/layout/Body.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { Component } from "solid-js";
|
||||
import { DivProps } from "~/components/common";
|
||||
|
||||
export const BodyRegion: Component<DivProps> = (props) => {
|
||||
return (
|
||||
<div class="min-h-full" {...props}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
31
packages/solid/src/components/layout/Navigation/Desktop.tsx
Normal file
31
packages/solid/src/components/layout/Navigation/Desktop.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Component } from "solid-js";
|
||||
import LogoLight from "/icons/zh/appbar_desktop_light.svg";
|
||||
import LogoDark from "/icons/zh/appbar_desktop_dark.svg";
|
||||
import { DynamicImage } from "~/components/utils/DynamicImage";
|
||||
import {
|
||||
AppBar,
|
||||
AppBarLeadingElement,
|
||||
AppBarSearchBox,
|
||||
AppBarSearchContainer,
|
||||
AppBarTrailingElement,
|
||||
AppBarTrailingElementGroup,
|
||||
IconButton
|
||||
} from "@m3-components/solid";
|
||||
|
||||
export const NavigationDesktop: Component = () => {
|
||||
return (
|
||||
<AppBar class="hidden lg:flex h-20 xl:h-22 2xl:h-24" variant="search">
|
||||
<AppBarLeadingElement class="h-full grow shrink basis-0">
|
||||
<DynamicImage class="lg:block h-full" darkSrc={LogoDark} lightSrc={LogoLight} />
|
||||
</AppBarLeadingElement>
|
||||
<AppBarSearchContainer>
|
||||
<AppBarSearchBox class="mx-auto text-center" placeholder="搜索" />
|
||||
</AppBarSearchContainer>
|
||||
<AppBarTrailingElementGroup class="h-full grow shrink basis-0">
|
||||
<AppBarTrailingElement>
|
||||
<IconButton></IconButton>
|
||||
</AppBarTrailingElement>
|
||||
</AppBarTrailingElementGroup>
|
||||
</AppBar>
|
||||
);
|
||||
};
|
||||
@ -1,6 +1,4 @@
|
||||
import { Component, createEffect, createMemo, createSignal, For, on, onMount } from "solid-js";
|
||||
import { HomeIcon } from "../icons/Home";
|
||||
import { MusicIcon } from "../icons/Music";
|
||||
import { Component, createEffect, createSignal, For } from "solid-js";
|
||||
import {
|
||||
NavigationRailFAB,
|
||||
NavigationRail,
|
||||
@ -12,78 +10,14 @@ import {
|
||||
AppBarSearchBox,
|
||||
AppBarTrailingElementGroup,
|
||||
AppBarTrailingElement,
|
||||
IconButton, AppBarSearchContainer
|
||||
IconButton,
|
||||
AppBarSearchContainer
|
||||
} from "@m3-components/solid";
|
||||
import { A } from "@solidjs/router";
|
||||
import { AlbumIcon } from "~/components/icons/Album";
|
||||
import { SearchIcon } from "../icons/Search";
|
||||
import { SearchIcon } from "~/components/icons/Search";
|
||||
import { Portal } from "solid-js/web";
|
||||
import { animate, createTimer, utils } from "animejs";
|
||||
import { tv } from "tailwind-variants";
|
||||
|
||||
export const [activeTab, setActiveTab] = createSignal(-1);
|
||||
export const [navigationExpanded, setNavigationExpanded] = createSignal(false);
|
||||
|
||||
interface Action {
|
||||
icon: Component;
|
||||
label: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
export const actions: Action[] = [
|
||||
{
|
||||
icon: HomeIcon,
|
||||
label: "主页",
|
||||
href: "/"
|
||||
},
|
||||
{
|
||||
icon: MusicIcon,
|
||||
label: "歌曲",
|
||||
href: "/songs"
|
||||
},
|
||||
{
|
||||
icon: AlbumIcon,
|
||||
label: "专辑",
|
||||
href: "/albums"
|
||||
}
|
||||
];
|
||||
|
||||
export const actionsEn: Action[] = [
|
||||
{
|
||||
icon: HomeIcon,
|
||||
label: "Home",
|
||||
href: "/en/"
|
||||
},
|
||||
{
|
||||
icon: MusicIcon,
|
||||
label: "Songs",
|
||||
href: "/en/songs"
|
||||
},
|
||||
{
|
||||
icon: AlbumIcon,
|
||||
label: "Albums",
|
||||
href: "/en/albums"
|
||||
}
|
||||
];
|
||||
|
||||
export const tabMap = {
|
||||
"/": 0,
|
||||
"/song*": 1,
|
||||
"/song/**/*": 1,
|
||||
"/albums": 2,
|
||||
"/album/**/*": 2,
|
||||
"/en/": 0,
|
||||
"/en/songs": 1,
|
||||
"/en/song*": 1,
|
||||
"/en/song/**/*": 1,
|
||||
"/en/albums": 2,
|
||||
"/en/album/**/*": 2
|
||||
};
|
||||
|
||||
const searchT = {
|
||||
zh: "搜索",
|
||||
en: "Search"
|
||||
};
|
||||
import { animate } from "animejs";
|
||||
import { actions, actionsEn, activeTab, navigationExpanded, searchT, setActiveTab, setNavigationExpanded } from ".";
|
||||
|
||||
export const NavigationMobile: Component<{ lang?: "zh" | "en" }> = (props) => {
|
||||
const [el, setEl] = createSignal<HTMLElement | null>(null);
|
||||
@ -119,7 +53,7 @@ export const NavigationMobile: Component<{ lang?: "zh" | "en" }> = (props) => {
|
||||
<AppBarLeadingElement>
|
||||
<NavigationRailMenu class="invisible" />
|
||||
</AppBarLeadingElement>
|
||||
<AppBarSearchContainer class="w-[calc(100%-7.9rem)]">
|
||||
<AppBarSearchContainer class="max-sm:w-[calc(100%-7.9rem)]">
|
||||
<AppBarSearchBox placeholder="搜索" />
|
||||
</AppBarSearchContainer>
|
||||
<AppBarTrailingElementGroup>
|
||||
@ -166,4 +100,4 @@ export const NavigationMobile: Component<{ lang?: "zh" | "en" }> = (props) => {
|
||||
</Portal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
};
|
||||
66
packages/solid/src/components/layout/Navigation/index.tsx
Normal file
66
packages/solid/src/components/layout/Navigation/index.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { Component, createSignal } from "solid-js";
|
||||
import { AlbumIcon, HomeIcon, MusicIcon } from "~/components/icons";
|
||||
|
||||
export const [activeTab, setActiveTab] = createSignal(-1);
|
||||
export const [navigationExpanded, setNavigationExpanded] = createSignal(false);
|
||||
|
||||
interface Action {
|
||||
icon: Component;
|
||||
label: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
export const actions: Action[] = [
|
||||
{
|
||||
icon: HomeIcon,
|
||||
label: "主页",
|
||||
href: "/"
|
||||
},
|
||||
{
|
||||
icon: MusicIcon,
|
||||
label: "歌曲",
|
||||
href: "/songs"
|
||||
},
|
||||
{
|
||||
icon: AlbumIcon,
|
||||
label: "专辑",
|
||||
href: "/albums"
|
||||
}
|
||||
];
|
||||
|
||||
export const actionsEn: Action[] = [
|
||||
{
|
||||
icon: HomeIcon,
|
||||
label: "Home",
|
||||
href: "/en/"
|
||||
},
|
||||
{
|
||||
icon: MusicIcon,
|
||||
label: "Songs",
|
||||
href: "/en/songs"
|
||||
},
|
||||
{
|
||||
icon: AlbumIcon,
|
||||
label: "Albums",
|
||||
href: "/en/albums"
|
||||
}
|
||||
];
|
||||
|
||||
export const tabMap = {
|
||||
"/": 0,
|
||||
"/song*": 1,
|
||||
"/song/**/*": 1,
|
||||
"/albums": 2,
|
||||
"/album/**/*": 2,
|
||||
"/en/": 0,
|
||||
"/en/songs": 1,
|
||||
"/en/song*": 1,
|
||||
"/en/song/**/*": 1,
|
||||
"/en/albums": 2,
|
||||
"/en/album/**/*": 2
|
||||
};
|
||||
|
||||
export const searchT = {
|
||||
zh: "搜索",
|
||||
en: "Search"
|
||||
};
|
||||
28
packages/solid/src/components/layout/index.tsx
Normal file
28
packages/solid/src/components/layout/index.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { NavigationMobile } from "./Navigation/Mobile";
|
||||
import { DivProps } from "../common";
|
||||
import { Component } from "solid-js";
|
||||
import { BeforeLeaveEventArgs, useBeforeLeave } from "@solidjs/router";
|
||||
import { refreshTab } from "~/app";
|
||||
import { NavigationDesktop } from "./Navigation/Desktop";
|
||||
import { BodyRegion } from "./Body";
|
||||
|
||||
interface LayoutProps extends DivProps {
|
||||
lang?: "zh" | "en";
|
||||
}
|
||||
|
||||
export const Layout: Component<LayoutProps> = (props) => {
|
||||
useBeforeLeave((e: BeforeLeaveEventArgs) => {
|
||||
if (typeof e.to === "number") {
|
||||
refreshTab(e.to.toString());
|
||||
return;
|
||||
}
|
||||
refreshTab(e.to);
|
||||
});
|
||||
return (
|
||||
<div class="relatve w-screen min-h-screen">
|
||||
<NavigationMobile lang={props.lang} />
|
||||
<NavigationDesktop />
|
||||
<BodyRegion>{props.children}</BodyRegion>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -1,58 +0,0 @@
|
||||
import { NavigationMobile } from "./Navigation";
|
||||
import { DivProps } from "../common";
|
||||
import { Component } from "solid-js";
|
||||
import { BeforeLeaveEventArgs, useBeforeLeave } from "@solidjs/router";
|
||||
import { refreshTab } from "~/app";
|
||||
import LogoLight from "/icons/zh/appbar_desktop_light.svg";
|
||||
import LogoDark from "/icons/zh/appbar_desktop_dark.svg";
|
||||
import { DynamicImage } from "~/components/utils/DynamicImage";
|
||||
import {
|
||||
AppBar,
|
||||
AppBarLeadingElement,
|
||||
AppBarSearchBox,
|
||||
AppBarSearchContainer,
|
||||
AppBarTrailingElement,
|
||||
AppBarTrailingElementGroup,
|
||||
IconButton
|
||||
} from "@m3-components/solid";
|
||||
|
||||
export const BodyRegion: Component<DivProps> = (props) => {
|
||||
return (
|
||||
<div class="pt-12 px-4" {...props}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface LayoutProps extends DivProps {
|
||||
lang?: "zh" | "en";
|
||||
}
|
||||
|
||||
export const Layout: Component<LayoutProps> = (props) => {
|
||||
useBeforeLeave((e: BeforeLeaveEventArgs) => {
|
||||
if (typeof e.to === "number") {
|
||||
refreshTab(e.to.toString());
|
||||
return;
|
||||
}
|
||||
refreshTab(e.to);
|
||||
});
|
||||
return (
|
||||
<div class="relatve w-screen min-h-screen">
|
||||
<NavigationMobile lang={props.lang} />
|
||||
<AppBar class="hidden lg:flex h-20 xl:h-22 2xl:h-24" variant="search">
|
||||
<AppBarLeadingElement class="h-full grow shrink basis-0">
|
||||
<DynamicImage class="lg:block h-full" darkSrc={LogoDark} lightSrc={LogoLight} />
|
||||
</AppBarLeadingElement>
|
||||
<AppBarSearchContainer>
|
||||
<AppBarSearchBox class="mx-auto text-center" placeholder="搜索" />
|
||||
</AppBarSearchContainer>
|
||||
<AppBarTrailingElementGroup class="h-full grow shrink basis-0">
|
||||
<AppBarTrailingElement>
|
||||
<IconButton></IconButton>
|
||||
</AppBarTrailingElement>
|
||||
</AppBarTrailingElementGroup>
|
||||
</AppBar>
|
||||
<BodyRegion>{props.children}</BodyRegion>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -1,21 +1,14 @@
|
||||
import { Button } from "@m3-components/solid";
|
||||
import { A } from "@solidjs/router";
|
||||
import { tv } from "tailwind-variants";
|
||||
import { navigationExpanded } from "~/components/shell/Navigation";
|
||||
import { Component, splitProps } from "solid-js";
|
||||
import { ElementProps } from "../common";
|
||||
|
||||
export const TabSwitcher: Component<ElementProps> = (props) => {
|
||||
const [_v, rest] = splitProps(props, ["class"]);
|
||||
|
||||
export const TabSwitcher = () => {
|
||||
const tabsContainerStyle = tv({
|
||||
base: "w-full lg:w-48 gap-4 flex lg:flex-col items-center",
|
||||
variants: {
|
||||
expanded: {
|
||||
true: "lg:self-start xl:self-center",
|
||||
false: "self-center"
|
||||
}
|
||||
}
|
||||
});
|
||||
return (
|
||||
<nav class="flex flex-col lg:h-screen lg:px-6 lg:pt-12">
|
||||
<div class={tabsContainerStyle({ expanded: navigationExpanded() })}>
|
||||
<nav class="flex flex-col" {...rest}>
|
||||
<div class="w-full lg:w-48 gap-4 flex lg:flex-col items-center lg:self-center 2xl:self-end">
|
||||
<A class="w-full" href="../info">
|
||||
<Button class="w-full" variant="filled">
|
||||
信息
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Title } from "@solidjs/meta";
|
||||
import { HttpStatusCode } from "@solidjs/start";
|
||||
import { Layout } from "~/components/shell/Layout";
|
||||
import { Layout } from "~/components/layout";
|
||||
import { A } from "@solidjs/router";
|
||||
|
||||
export default function NotFound() {
|
||||
@ -8,7 +8,7 @@ export default function NotFound() {
|
||||
<Layout>
|
||||
<Title>找不到页面啾~</Title>
|
||||
<HttpStatusCode code={404} />
|
||||
<main class="w-full h-screen flex flex-col flex-grow items-center justify-center gap-8">
|
||||
<main class="w-full h-[calc(100vh-6rem)] flex flex-col flex-grow items-center justify-center gap-8">
|
||||
<h1 class="text-9xl font-thin">404</h1>
|
||||
<p class="text-xl font-medium">咦……页面去哪里了(゚Д゚≡゚д゚)!?</p>
|
||||
<A href="/">
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Layout } from "~/components/shell/Layout";
|
||||
import { Layout } from "~/components/layout";
|
||||
import { query } from "@solidjs/router";
|
||||
import { Card, CardContent, CardMedia, Typography } from "@m3-components/solid";
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Layout } from "~/components/shell/Layout";
|
||||
import { Layout } from "~/components/layout";
|
||||
import { dbMain } from "~/drizzle";
|
||||
import { bilibiliMetadata, latestVideoSnapshot } from "~db/main/schema";
|
||||
import { and, desc, eq, gte, lt } from "drizzle-orm";
|
||||
|
||||
@ -9,7 +9,7 @@ import { bilibiliMetadata, videoSnapshot } from "~db/main/schema";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
import { BilibiliMetadataType, VideoSnapshotType } from "~db/outerSchema";
|
||||
import { Context, useRequestContext } from "~/components/requestContext";
|
||||
import { Layout } from "~/components/shell/Layout";
|
||||
import { Layout } from "~/components/layout";
|
||||
|
||||
async function getAllSnapshots(aid: number, context: Context) {
|
||||
"use server";
|
||||
|
||||
@ -1,17 +1,37 @@
|
||||
import { Layout } from "~/components/shell/Layout";
|
||||
import { Card, CardContent, CardMedia, Typography } from "@m3-components/solid";
|
||||
import { Layout } from "~/components/layout";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardMedia,
|
||||
ExtendedFAB,
|
||||
FloatingActionButton,
|
||||
Typography
|
||||
} from "@m3-components/solid";
|
||||
|
||||
import { TabSwitcher } from "~/components/song/TabSwitcher";
|
||||
import { EditIcon, HomeIcon, MusicIcon } from "~/components/icons";
|
||||
|
||||
export default function Info() {
|
||||
return (
|
||||
<Layout>
|
||||
<title></title>
|
||||
<div
|
||||
class="w-full sm:w-120 sm:mx-auto lg:w-full lg:grid lg:grid-cols-[1fr_560px_minmax(300px,_1fr)]
|
||||
class="pt-12 px-4 w-full sm:w-120 sm:mx-auto lg:w-full 2xl:w-360 lg:grid lg:grid-cols-[1fr_560px_1fr]
|
||||
xl:grid-cols-[1fr_648px_1fr]"
|
||||
>
|
||||
<nav class="hidden opacity-0 pointer-events-none lg:block xl:opacity-100 xl:pointer-events-auto pt-4"></nav>
|
||||
<nav class="hidden pointer-events-none lg:block xl:pointer-events-auto pt-4">
|
||||
<div class="inline-flex flex-col gap-2">
|
||||
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
|
||||
<HomeIcon class="w-5 h-5 text-xl -translate-y-0.25" />
|
||||
<span>主页</span>
|
||||
</Button>
|
||||
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
|
||||
<MusicIcon class="w-5 h-5 text-xl" />
|
||||
<span>歌曲</span>
|
||||
</Button>
|
||||
</div>
|
||||
</nav>
|
||||
<main>
|
||||
<Card variant="outlined" class="w-full">
|
||||
<CardMedia
|
||||
@ -57,7 +77,12 @@ export default function Info() {
|
||||
</Typography.Body>
|
||||
</article>
|
||||
</main>
|
||||
<div class="hidden lg:block">
|
||||
<div class="hidden lg:flex flex-col px-6">
|
||||
<div class="w-48 self-center 2xl:self-end flex justify-end mb-6">
|
||||
<ExtendedFAB position="unset" size="small" text="编辑" color="primary">
|
||||
<EditIcon />
|
||||
</ExtendedFAB>
|
||||
</div>
|
||||
<TabSwitcher />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Layout } from "~/components/shell/Layout";
|
||||
import { Layout } from "~/components/layout";
|
||||
|
||||
export default function SongsHome() {
|
||||
return (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user