Compare commits

...

6 Commits

Author SHA1 Message Date
鲁树人
b33ffa6ca7 build: include _redirects for netlify deployment
All checks were successful
Build and Deploy / build (push) Successful in 2m4s
2025-05-19 10:00:53 +09:00
鲁树人
09c1bc474e child: remove base 2025-05-19 09:58:13 +09:00
鲁树人
e0b3bd60c2 chore: update wording for settings 2025-05-19 09:51:00 +09:00
鲁树人
6371c58cd5 fix: theme support 2025-05-19 09:50:52 +09:00
鲁树人
98f1be9ac7 fix: default sub-nav to align top on large screen 2025-05-19 09:26:54 +09:00
鲁树人
3541af7a96 refactor: deep link for faq 2025-05-19 09:23:14 +09:00
23 changed files with 344 additions and 155 deletions

2
public/_redirects Normal file
View File

@ -0,0 +1,2 @@
# Support SPA routing in Netlify
/* /index.html 200

View File

@ -1,8 +1,43 @@
@import 'tailwindcss';
@plugin "daisyui" {
themes:
emerald --default,
dracula --prefersdark;
themes: dracula --prefersdark;
}
/* theme: https://daisyui.com/theme-generator/#theme=eJx1kuFupCAUhV-FmGyym1TCBQHt2zB67Zg6MAFNu2323ZdhGkdH_Annu9dzjnwX1lyweC1OZjS2xa54KcrSm26YQxlwxHZyPsqMSo-XtdgPOHZZ5eQ-t_dh-MLtMr7VHrsewsn5Dm80XD_TRYfX6Xw7p5N1Q8CfU-tG58vQnjFFGYe385Sgu3AyAUtgLErufWzPv5v6F2GE_Xlm-JpRkaGMAeG1okLLHS3WNL_TinBVUSlgR7fOTminZYKznQeL8-TNuCBCHyG7bZlEg-3dolfJHzRN9CepEvWaDHPbYggLLO-wrAjIGEo1a_jDeDvYtwVWqSfQDZE1FbBZjN6n__2z9haH8koSrqng8tnsPlQaYFARLiuqWJUxfTTEgYBSFEBkzOfri0OcNJJyrXchDr0JAjHMJvXVDxfj_z4aYqkhqAnUFdVPMTBu7jI4j0-JA9V8E8DE0CsXElKl0Tco2giZsXGUNbYKNYv7s24Op-IDYozWOuNqPyPSjOC3jjSkVjvszTxGZvIzvhRXjz36ED_5Xrz2Zgz47z_whE0z */
@plugin "daisyui/theme" {
name: 'balanced';
default: true;
prefersdark: false;
color-scheme: 'light';
--color-base-100: oklch(98% 0 0);
--color-base-200: oklch(96% 0.001 286.375);
--color-base-300: oklch(92% 0.006 264.531);
--color-base-content: oklch(20% 0 0);
--color-primary: oklch(60% 0.118 184.704);
--color-primary-content: oklch(98% 0.014 180.72);
--color-secondary: oklch(60% 0.126 221.723);
--color-secondary-content: oklch(98% 0.019 200.873);
--color-accent: oklch(51% 0.222 16.935);
--color-accent-content: oklch(93% 0.032 17.717);
--color-neutral: oklch(37% 0 0);
--color-neutral-content: oklch(98% 0 0);
--color-info: oklch(42% 0.199 265.638);
--color-info-content: oklch(97% 0.014 254.604);
--color-success: oklch(52% 0.154 150.069);
--color-success-content: oklch(97% 0.021 166.113);
--color-warning: oklch(66% 0.179 58.318);
--color-warning-content: oklch(98% 0.022 95.277);
--color-error: oklch(57% 0.245 27.325);
--color-error-content: oklch(97% 0.013 17.38);
--radius-selector: 0.5rem;
--radius-field: 0.5rem;
--radius-box: 0.5rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 1;
--noise: 1;
}
@theme {
--font-display:
@ -19,3 +54,14 @@
display: flex;
flex-direction: column;
}
h1,
h2,
h3,
h4,
h5,
h6 {
&:hover > a[data-anchor] {
opacity: 0.75;
}
}

View File

@ -13,6 +13,8 @@ import { FaqTab } from '~/tabs/FaqTab';
import { SETTINGS_TABS } from '~/features/settings/settingsTabs';
import { Bounce, ToastContainer } from 'react-toastify';
import { SettingsHome } from '~/features/settings/SettingsHome';
import { FAQ_PAGES } from '~/faq/FAQPages';
import { FaqHome } from '~/faq/FaqHome';
// Private to this file only.
const store = setupStore();
@ -49,7 +51,12 @@ export function AppRoot() {
<Route key={key} path={key} Component={Tab} />
))}
</Route>
<Route path="/questions" Component={FaqTab} />
<Route path="/questions" Component={FaqTab}>
<Route index Component={FaqHome} />
{FAQ_PAGES.map(({ id, Component }) => (
<Route key={id} path={id} Component={Component} />
))}
</Route>
</Routes>
</main>

View File

@ -0,0 +1,9 @@
import { RiLink } from 'react-icons/ri';
export function HeaderAnchor({ id }: { id: string }) {
return (
<a href={`#${id}`} data-anchor={id} className="absolute -left-6 opacity-10 transition-opacity duration-200">
<RiLink className="max-h-[.75em]" />
</a>
);
}

View File

@ -1,4 +1,5 @@
import React from 'react';
import { HeaderAnchor } from './HeaderAnchor';
export interface HeaderProps {
children: React.ReactNode;
@ -6,9 +7,20 @@ export interface HeaderProps {
className?: string;
}
const commonHeaderClasses = 'relative flex items-center pt-3 pb-1 font-bold';
export function Header2({ children, className, id }: HeaderProps) {
return (
<h2 id={id} className={`${commonHeaderClasses} text-3xl border-b border-base-300 ${className}`}>
{id && <HeaderAnchor id={id} />}
{children}
</h2>
);
}
export function Header3({ children, className, id }: HeaderProps) {
return (
<h3 id={id} className={`text-2xl pt-3 pb-1 font-bold border-b border-base-300 ${className}`}>
<h3 id={id} className={`${commonHeaderClasses} text-2xl border-b border-base-300 ${className}`}>
{id && <HeaderAnchor id={id} />}
{children}
</h3>
);
@ -16,7 +28,8 @@ export function Header3({ children, className, id }: HeaderProps) {
export function Header4({ children, className, id }: HeaderProps) {
return (
<h4 id={id} className={`text-xl pt-3 pb-1 font-semibold ${className}`}>
<h4 id={id} className={`${commonHeaderClasses} text-xl ${className}`}>
{id && <HeaderAnchor id={id} />}
{children}
</h4>
);
@ -24,7 +37,8 @@ export function Header4({ children, className, id }: HeaderProps) {
export function Header5({ children, className, id }: HeaderProps) {
return (
<h5 id={id} className={`text-lg pt-3 pb-1 font-semibold ${className}`}>
<h5 id={id} className={`${commonHeaderClasses} text-lg ${className}`}>
{id && <HeaderAnchor id={id} />}
{children}
</h5>
);

View File

@ -0,0 +1,43 @@
import classNames from 'classnames';
import { useRef } from 'react';
export interface ImageFigureProps {
srcSet: string;
alt: string;
className?: string;
loading?: 'lazy' | 'eager';
children?: React.ReactNode;
}
export function ImageFigure({ alt, srcSet, children, className, loading }: ImageFigureProps) {
const refDialog = useRef<HTMLDialogElement>(null);
return (
<figure className={classNames(className, 'inline-flex flex-col items-center')}>
<img
className={`rounded-md cursor-pointer border border-base-300 max-h-48`}
loading={loading}
srcSet={srcSet}
alt={alt}
onClick={() => refDialog?.current?.showModal()}
/>
{children && <figcaption className="text-sm text-base-content/70">{children}</figcaption>}
<dialog ref={refDialog} className="modal text-left">
<div className="modal-box max-w-[50vw]">
<form method="dialog">
<button className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
<h3 className="font-bold text-lg"></h3>
<figure className="flex flex-col justify-center text-center">
<img srcSet={srcSet} alt={alt} />
{children && <figcaption className="text-sm text-base-content/70">{children}</figcaption>}
</figure>
</div>
<form method="dialog" className="modal-backdrop">
<button></button>
</form>
</dialog>
</figure>
);
}

View File

@ -1,3 +1,4 @@
import classNames from 'classnames';
import React, { Fragment, useId } from 'react';
export type InstructionTab = {
@ -8,19 +9,24 @@ export type InstructionTab = {
export interface InstructionsTabsProps {
tabs: InstructionTab[];
limitHeight?: boolean;
}
export function InstructionsTabs({ tabs }: InstructionsTabsProps) {
export function InstructionsTabs({ limitHeight = false, tabs }: InstructionsTabsProps) {
const id = useId();
return (
<div className="tabs tabs-lift max-h-[32rem] pb-4">
<div className={classNames('tabs tabs-lift pb-4', { 'max-h-[32rem]': limitHeight })}>
{tabs.map(({ id: _tabId, label, content }, index) => (
<Fragment key={_tabId}>
<label className="tab">
<input type="radio" name={id} defaultChecked={index === 0} />
{label}
</label>
<div className="tab-content border-base-300 bg-base-100 px-4 py-2 overflow-y-auto max-h-[30rem]">
<div
className={classNames('tab-content border-base-300 bg-base-100 px-4 py-2 overflow-y-auto', {
'max-h-[30rem]': limitHeight,
})}
>
{content}
</div>
</Fragment>

View File

@ -0,0 +1,75 @@
import { ExtLink } from '~/components/ExtLink';
import { Header2, Header3, Header4 } from '~/components/HelpText/Headers';
import { VQuote } from '~/components/HelpText/VQuote';
import { RiErrorWarningLine } from 'react-icons/ri';
import LdPlayerSettingsMisc2x from './assets/ld_settings_misc@2x.webp';
import MumuSettingsMisc2x from './assets/mumu_settings_misc@2x.webp';
import { ImageFigure } from '~/components/ImageFigure';
export function AndroidEmulatorFAQ() {
return (
<>
<Header2></Header2>
<p className="mb-2">便 root </p>
<ul className="list-disc pl-6 mb-2">
<li>
<ExtLink href="https://mumu.163.com/"> MuMu 12</ExtLink> - Hyper-V
</li>
<li>
<ExtLink href="https://www.ldmnq.com/"> 9</ExtLink>
</li>
</ul>
<p className="mb-2">广使</p>
<div className="my-2 alert alert-warning">
<RiErrorWarningLine className="text-lg" />
<p>
使<strong></strong>
</p>
</div>
<p className="mb-2">使</p>
<Header3 id="enable-root"> root</Header3>
<p className="mb-2"> root </p>
<Header4 id="root-mumu"> MuMu </Header4>
<ul className="list-disc pl-6">
<li>
<VQuote></VQuote>
</li>
<li>
<VQuote></VQuote>
</li>
<li>
<VQuote>Root权限</VQuote>
</li>
</ul>
<div>
<ImageFigure className="ml-2" alt="网易木木模拟器设置界面" loading="lazy" srcSet={`${MumuSettingsMisc2x} 2x`}>
</ImageFigure>
</div>
<Header4 id="root-ld"></Header4>
<ul className="list-disc pl-6">
<li>
<VQuote></VQuote>
</li>
<li>
<VQuote></VQuote>
</li>
<li>
<VQuote>ROOT </VQuote><VQuote></VQuote>
</li>
</ul>
<div>
<ImageFigure className="ml-2" alt="雷电模拟器设置界面" loading="lazy" srcSet={`${LdPlayerSettingsMisc2x} 2x`}>
</ImageFigure>
</div>
</>
);
}

20
src/faq/FAQPages.tsx Normal file
View File

@ -0,0 +1,20 @@
import type { ComponentType } from 'react';
import { QQMusicFAQ } from './QQMusicFAQ';
import { KuwoFAQ } from './KuwoFAQ';
import { KugouFAQ } from './KugouFAQ';
import { OtherFAQ } from './OtherFAQ';
import { AndroidEmulatorFAQ } from './AndroidEmulatorFAQ';
export type FAQEntry = {
id: string;
name: string;
Component: ComponentType;
};
export const FAQ_PAGES: FAQEntry[] = [
{ id: 'qqmusic', name: 'QQ 音乐', Component: QQMusicFAQ },
{ id: 'kuwo', name: '酷我音乐', Component: KuwoFAQ },
{ id: 'kugou', name: '酷狗音乐', Component: KugouFAQ },
{ id: 'android-emu', name: '安卓模拟器', Component: AndroidEmulatorFAQ },
{ id: 'other', name: '其它问题', Component: OtherFAQ },
];

14
src/faq/FaqHome.tsx Normal file
View File

@ -0,0 +1,14 @@
import { ExtLink } from '~/components/ExtLink';
export function FaqHome() {
return (
<div className="flex flex-col gap-4">
<h1 className="text-2xl font-bold"></h1>
<p></p>
<p>
访
<ExtLink href={'https://t.me/unlock_music_chat'}>- </ExtLink>
</p>
</div>
);
}

View File

@ -1,4 +1,4 @@
import { Header4 } from '~/components/HelpText/Headers';
import { Header2, Header3 } from '~/components/HelpText/Headers';
import { SegmentKeyImportInstructions } from './SegmentKeyImportInstructions';
import { KugouAllInstructions } from '~/features/settings/panels/Kugou/KugouAllInstructions.tsx';
import { RiErrorWarningLine } from 'react-icons/ri';
@ -6,19 +6,19 @@ import { RiErrorWarningLine } from 'react-icons/ri';
export function KugouFAQ() {
return (
<>
<Header4></Header4>
<p>
<Header2></Header2>
<Header3 id="failed"></Header3>
<p className="mb-2">
<code>kgg</code> Windows
</p>
<p className="my-4"></p>
<p className="mb-2"></p>
<div className="p-2 @container">
<div className="alert alert-warning">
<RiErrorWarningLine className="size-6" />
<p> root </p>
</div>
<div className="alert alert-warning mb-2">
<RiErrorWarningLine className="size-6" />
<p> root </p>
</div>
<Header3 id="keys"></Header3>
<SegmentKeyImportInstructions tab="酷狗密钥" clientInstructions={<KugouAllInstructions />} />
</>
);

View File

@ -1,4 +1,4 @@
import { Header4 } from '~/components/HelpText/Headers';
import { Header2, Header3 } from '~/components/HelpText/Headers';
import { VQuote } from '~/components/HelpText/VQuote';
import { SegmentTryOfficialPlayer } from './SegmentTryOfficialPlayer';
import { HiWord } from '~/components/HelpText/HiWord';
@ -9,9 +9,10 @@ import { RiErrorWarningLine } from 'react-icons/ri';
export function KuwoFAQ() {
return (
<>
<Header4></Header4>
<Header2></Header2>
<Header3 id="failed"></Header3>
<SegmentTryOfficialPlayer />
<p className="my-4">
<p className="mb-2">
<HiWord></HiWord>
<VQuote>
<strong></strong>
@ -22,10 +23,11 @@ export function KuwoFAQ() {
</VQuote>
</p>
<p className="my-4"></p>
<p className="my-4">PC平台暂未推出使用新版加密的音质</p>
<p className="mb-2"></p>
<p className="mb-2">PC平台暂未推出使用新版加密的音质</p>
<div className="alert alert-warning mb-4">
<Header3 id="keys"></Header3>
<div className="alert alert-warning my-2">
<RiErrorWarningLine className="text-2xl" />
<div>
<p> root </p>

View File

@ -1,20 +1,18 @@
import { ExtLink } from '~/components/ExtLink';
import { Header4, Header5 } from '~/components/HelpText/Headers';
import { VQuote } from '~/components/HelpText/VQuote';
import { Header2, Header3, Header4 } from '~/components/HelpText/Headers';
import { ProjectIssue } from '~/components/ProjectIssue';
import { RiErrorWarningLine } from 'react-icons/ri';
import LdPlayerSettingsMisc2x from './assets/ld_settings_misc@2x.webp';
import MumuSettingsMisc2x from './assets/mumu_settings_misc@2x.webp';
import { NavLink } from 'react-router';
export function OtherFAQ() {
return (
<>
<Header4></Header4>
<Header2></Header2>
<Header3 id="metadata"></Header3>
<p></p>
<p>使</p>
<Header4></Header4>
<Header3 id="batch-dl"></Header3>
<p>
{'暂时没有实现,不过你可以在 '}
<ProjectIssue id={34} title="[UI] 全部下载功能" />
@ -23,11 +21,11 @@ export function OtherFAQ() {
{' 追踪该问题。'}
</p>
<Header4>安卓: 浏览器支持说明</Header4>
<Header3 id="android-browsers">安卓: 浏览器支持说明</Header3>
<p> 使 Chrome Firefox </p>
<div className="flex flex-col md:flex-row gap-2 md:gap-8">
<div>
<Header5></Header5>
<Header4></Header4>
<ul className="list-disc list-inside pl-2">
<li>Via </li>
<li></li>
@ -36,7 +34,7 @@ export function OtherFAQ() {
</div>
<div>
<Header5></Header5>
<Header4></Header4>
<ul className="list-disc list-inside pl-2">
<li></li>
<li></li>
@ -45,70 +43,20 @@ export function OtherFAQ() {
</div>
</div>
<Header4>安卓: root </Header4>
<Header3 id="android-root"> root</Header3>
<p>
root 使
使 NFC
</p>
<p className="my-2">使</p>
<p className="my-2">
root 便
<VQuote>
<ExtLink href="https://mumu.163.com/"> MuMu 12</ExtLink>
</VQuote>
<VQuote>
<ExtLink href="https://www.ldmnq.com/"> 9</ExtLink>
</VQuote>
使
<NavLink className="link link-info" to="/questions/android-emu">
</NavLink>
</p>
<div className="my-4 alert alert-warning">
<RiErrorWarningLine className="text-lg" />
<div>
<p>
使<strong></strong>
</p>
<p>使</p>
</div>
</div>
<p> root </p>
<div className="grid grid-cols-1 gap-2 md:gap-4 lg:grid-cols-2">
<div>
<Header5> MuMu模拟器</Header5>
<ul className="list-disc pl-6">
<li>
<VQuote></VQuote>
</li>
<li>
<VQuote></VQuote>
</li>
<li>
<VQuote>Root权限</VQuote>
</li>
</ul>
<img className="rounded-md border border-base-300" loading="lazy" srcSet={`${MumuSettingsMisc2x} 2x`} />
</div>
<div>
<Header5></Header5>
<ul className="list-disc pl-6">
<li>
<VQuote></VQuote>
</li>
<li>
<VQuote></VQuote>
</li>
<li>
<VQuote>ROOT </VQuote><VQuote></VQuote>
</li>
</ul>
<img className="rounded-md border border-base-300" loading="lazy" srcSet={`${LdPlayerSettingsMisc2x} 2x`} />
</div>
</div>
<Header4></Header4>
<Header3 id="projects"></Header3>
<ul className="list-disc pl-6">
<li>
<p>
@ -150,7 +98,7 @@ export function OtherFAQ() {
</li>
</ul>
<Header4></Header4>
<Header3 id="more-questions"></Header3>
<p className="flex flex-row gap-1">
<ExtLink href={'https://t.me/unlock_music_chat'}>- </ExtLink>

View File

@ -1,17 +1,24 @@
import { Header4 } from '~/components/HelpText/Headers';
import { Header2, Header3 } from '~/components/HelpText/Headers';
import { SegmentTryOfficialPlayer } from './SegmentTryOfficialPlayer';
import { QMCv2QQMusicAllInstructions } from '~/features/settings/panels/QMCv2/QMCv2QQMusicAllInstructions';
export function QQMusicFAQ() {
return (
<>
<Header4></Header4>
<Header2>QQ </Header2>
<Header3 id="failed"></Header3>
<SegmentTryOfficialPlayer />
<p className="my-4"></p>
<p className="mb-4">
<p className="mb-2"> QQ </p>
<p className="mb-2"></p>
<p className="mb-2"></p>
<Header3 id="about-download"></Header3>
<p></p>
<p className="my-2">
<strong></strong>使
</p>
<Header3 id="keys-or-downgrade"></Header3>
<QMCv2QQMusicAllInstructions />
</>
);

View File

@ -2,7 +2,7 @@ import { RiErrorWarningLine } from 'react-icons/ri';
export function SegmentTryOfficialPlayer({ className = '' }: { className?: string }) {
return (
<div className={`alert alert-warning ${className}`}>
<div className={`alert alert-warning my-2 ${className}`}>
<RiErrorWarningLine className="text-2xl" />
<p></p>
</div>

View File

@ -20,7 +20,7 @@ export function ResponsiveNav({
className={`@container/nav grow grid grid-cols-1 grid-rows-[auto_1fr] md:grid-rows-1 md:grid-cols-[10rem_1fr] ${className}`}
>
{/* Sidebar */}
<aside className={`bg-base-300 md:p-4 md:block ${navigationClassName}`}>{navigation}</aside>
<aside className={`bg-base-100 md:p-4 md:block ${navigationClassName}`}>{navigation}</aside>
{/* Main content */}
<div className={`p-4 grow ${contentClassName}`}>{children}</div>

View File

@ -0,0 +1,21 @@
import classNames from 'classnames';
import type { RefAttributes } from 'react';
import { NavLink, type NavLinkProps } from 'react-router';
const tabClassNames = ({ isActive }: { isActive: boolean }) =>
classNames(
'link inline-flex text-nowrap mb-[-2px] no-underline w-full',
'border-b-2 md:border-b-0 md:border-r-2',
'tab md:grow',
{
'tab-active bg-accent/10 border-accent': isActive,
},
);
export function TabNavLink({ children, ...props }: NavLinkProps & RefAttributes<HTMLAnchorElement>) {
return (
<NavLink className={tabClassNames} role="tab" {...props}>
{children}
</NavLink>
);
}

View File

@ -1,12 +1,12 @@
import { useAppDispatch, useAppSelector } from '~/hooks';
import { commitStagingChange, discardStagingChanges } from './settingsSlice';
import { selectIsSettingsNotSaved } from './settingsSelector';
import { NavLink, Outlet } from 'react-router';
import { Outlet } from 'react-router';
import { SETTINGS_TABS } from '~/features/settings/settingsTabs.tsx';
import { MdOutlineSettingsBackupRestore } from 'react-icons/md';
import { toast } from 'react-toastify';
import { ResponsiveNav } from '../nav/ResponsiveNav';
import classNames from 'classnames';
import { TabNavLink } from '../nav/TabNavLink';
export function Settings() {
const dispatch = useAppDispatch();
@ -27,28 +27,18 @@ export function Settings() {
};
const isSettingsNotSaved = useAppSelector(selectIsSettingsNotSaved);
const tabClassNames = ({ isActive }: { isActive: boolean }) =>
classNames(
'link inline-flex text-nowrap mb-[-2px] no-underline w-full',
'border-b-2 md:border-b-0 md:border-r-2',
'tab md:grow',
{
'tab-active bg-accent/10 border-accent': isActive,
},
);
return (
<div className="flex flex-col flex-1 container w-full">
<ResponsiveNav
className="grow h-full overflow-auto"
contentClassName="flex flex-col overflow-auto"
navigationClassName="overflow-x-auto pb-[2px] md:pb-0 h-full md:items-center [&]:md:flex"
navigationClassName="overflow-x-auto pb-[2px] md:pb-0 h-full items-start [&]:md:flex"
navigation={
<div role="tablist" className="tabs gap-1 flex-nowrap md:flex-col grow items-center">
{Object.entries(SETTINGS_TABS).map(([id, { name }]) => (
<NavLink className={tabClassNames} key={id} to={`/settings/${id}`} role="tab">
<TabNavLink key={id} to={`/settings/${id}`}>
{name}
</NavLink>
</TabNavLink>
))}
</div>
}

View File

@ -43,7 +43,7 @@ export function PanelKGGKey() {
<div className="container flex flex-col grow min-h-0 w-full">
<h2 className="text-2xl font-bold"> (KGG / KGM v5)</h2>
<p>使 KGG / KGM v5 </p>
<p>使 KGG / KGM v5 </p>
<h3 className="mt-2 text-xl font-bold"></h3>
<AddKey

View File

@ -43,6 +43,8 @@ export function PanelKWMv2Key() {
V2 <code>mflac</code> <code>mgg</code>
</p>
<p></p>
<h3 className="mt-2 text-xl font-bold"></h3>
<AddKey
addKey={addKey}
refContainer={refKeyContainer}

View File

@ -4,7 +4,7 @@ import { InstructionsMac } from './InstructionsMac';
import { InstructionsPC } from './InstructionsPC';
import { InstructionsTabs, InstructionTab } from '~/components/InstructionsTabs.tsx';
export function QMCv2QQMusicAllInstructions() {
export function QMCv2QQMusicAllInstructions({ limitHeight }: { limitHeight?: boolean }) {
const tabs: InstructionTab[] = [
{
id: 'android',
@ -16,5 +16,5 @@ export function QMCv2QQMusicAllInstructions() {
{ id: 'windows', label: 'Windows', content: <InstructionsPC /> },
];
return <InstructionsTabs tabs={tabs} />;
return <InstructionsTabs tabs={tabs} limitHeight={limitHeight} />;
}

View File

@ -1,43 +1,27 @@
import { ComponentType, Fragment } from 'react';
import { Header3 } from '~/components/HelpText/Headers';
import { KuwoFAQ } from '~/faq/KuwoFAQ';
import { OtherFAQ } from '~/faq/OtherFAQ';
import { QQMusicFAQ } from '~/faq/QQMusicFAQ';
import { KugouFAQ } from '~/faq/KugouFAQ.tsx';
type FAQEntry = {
id: string;
title: string;
Help: ComponentType;
};
const faqEntries: FAQEntry[] = [
{ id: 'qqmusic', title: 'QQ 音乐', Help: QQMusicFAQ },
{ id: 'kuwo', title: '酷我音乐', Help: KuwoFAQ },
{ id: 'kugou', title: '酷狗音乐', Help: KugouFAQ },
{ id: 'other', title: '其它问题', Help: OtherFAQ },
];
import { Outlet } from 'react-router';
import { FAQ_PAGES } from '~/faq/FAQPages';
import { ResponsiveNav } from '~/features/nav/ResponsiveNav';
import { TabNavLink } from '~/features/nav/TabNavLink';
export function FaqTab() {
return (
<section className="container pb-10 px-4">
<h2 className="text-3xl font-bold text-center"></h2>
<Header3></Header3>
<ul className="list-disc pl-6">
{faqEntries.map(({ id, title }) => (
<li key={id}>
<a className="link link-info no-underline" href={`#faq-${id}`}>
{title}
</a>
</li>
))}
</ul>
{faqEntries.map(({ id, title, Help }) => (
<Fragment key={id}>
<Header3 id={`faq-${id}`}>{title}</Header3>
<Help />
</Fragment>
))}
</section>
<div className="flex flex-col flex-1 container w-full">
<ResponsiveNav
className="grow h-full overflow-auto"
contentClassName="flex flex-col overflow-auto px-8"
navigationClassName="overflow-x-auto pb-[2px] md:pb-0 h-full md:items-start [&]:md:flex"
navigation={
<div role="tablist" className="tabs gap-1 flex-nowrap md:flex-col grow items-center">
{FAQ_PAGES.map(({ id, name }) => (
<TabNavLink key={id} to={`/questions/${id}`}>
{name}
</TabNavLink>
))}
</div>
}
>
<Outlet />
</ResponsiveNav>
</div>
);
}

View File

@ -40,7 +40,6 @@ export default defineConfig({
],
},
},
base: './',
optimizeDeps: {
exclude: ['@unlock-music/crypto', 'sql.js'],
},