このコミットが含まれているのは:
@@ -1,9 +1,8 @@
|
||||
import PrefetchLink from '@/components/PrefetchLink'
|
||||
import ResponsiveMarqueeText from '@/components/ResponsiveMarqueeText'
|
||||
import { LIGHT_COLOUR_SHADE, DARK_COLOUR_SHADE, TAG_COLOUR } from '@/consts'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import type { ComponentProps, FC, HTMLAttributes } from 'react'
|
||||
import type { ComponentProps, CSSProperties, FC, HTMLAttributes } from 'react'
|
||||
|
||||
import type { Tag } from '@/types'
|
||||
|
||||
@@ -36,15 +35,16 @@ const TagLink: FC<Props> = ({ tag,
|
||||
withWiki = true,
|
||||
withCount = true,
|
||||
className,
|
||||
style,
|
||||
title,
|
||||
...props }) => {
|
||||
const spanClass = cn (
|
||||
`text-${ TAG_COLOUR[tag.category] }-${ LIGHT_COLOUR_SHADE }`,
|
||||
`dark:text-${ TAG_COLOUR[tag.category] }-${ DARK_COLOUR_SHADE }`)
|
||||
const linkClass = cn (
|
||||
spanClass,
|
||||
`hover:text-${ TAG_COLOUR[tag.category] }-${ LIGHT_COLOUR_SHADE - 200 }`,
|
||||
`dark:hover:text-${ TAG_COLOUR[tag.category] }-${ DARK_COLOUR_SHADE - 200 }`)
|
||||
const colourStyle = {
|
||||
'--tag-link-colour': `var(--tag-colour-${ tag.category })`,
|
||||
'--tag-link-hover-colour': `var(--tag-colour-${ tag.category }-hover)`,
|
||||
...style,
|
||||
} as CSSProperties
|
||||
const spanClass = 'tag-link-colour'
|
||||
const linkClass = 'tag-link-colour tag-link-hover-colour'
|
||||
const textClass = 'group min-w-0 max-w-full overflow-hidden align-bottom'
|
||||
const rootClass =
|
||||
'inline-flex min-w-0 max-w-full flex-nowrap items-stretch align-baseline gap-x-1 md:items-baseline'
|
||||
@@ -63,7 +63,8 @@ const TagLink: FC<Props> = ({ tag,
|
||||
? (
|
||||
<PrefetchLink
|
||||
to={`/wiki/${ encodeURIComponent (tag.name) }`}
|
||||
className={linkClass}>
|
||||
className={linkClass}
|
||||
style={colourStyle}>
|
||||
?
|
||||
</PrefetchLink>)
|
||||
: (
|
||||
@@ -71,13 +72,15 @@ const TagLink: FC<Props> = ({ tag,
|
||||
? (
|
||||
<PrefetchLink
|
||||
to={`/materials/${ tag.materialId }`}
|
||||
className={linkClass}>
|
||||
className={linkClass}
|
||||
style={colourStyle}>
|
||||
?
|
||||
</PrefetchLink>)
|
||||
: (
|
||||
<PrefetchLink
|
||||
to={`/tags/${ tag.id }/deerjikists`}
|
||||
className={linkClass}>
|
||||
className={linkClass}
|
||||
style={colourStyle}>
|
||||
?
|
||||
</PrefetchLink>)))
|
||||
: (
|
||||
@@ -120,6 +123,7 @@ const TagLink: FC<Props> = ({ tag,
|
||||
<span
|
||||
title={textTitle}
|
||||
className={cn (spanClass, textClass, className)}
|
||||
style={colourStyle}
|
||||
{...props}>
|
||||
<ResponsiveMarqueeText
|
||||
text={tag.matchedAlias}
|
||||
@@ -134,6 +138,7 @@ const TagLink: FC<Props> = ({ tag,
|
||||
to={`/posts?${ (new URLSearchParams ({ tags: tag.name })).toString () }`}
|
||||
title={textTitle}
|
||||
className={cn (linkClass, textClass, className)}
|
||||
style={colourStyle}
|
||||
{...props}>
|
||||
<ResponsiveMarqueeText
|
||||
text={tag.name}
|
||||
@@ -144,6 +149,7 @@ const TagLink: FC<Props> = ({ tag,
|
||||
<span
|
||||
title={textTitle}
|
||||
className={cn (spanClass, textClass, className)}
|
||||
style={colourStyle}
|
||||
{...props}>
|
||||
<ResponsiveMarqueeText
|
||||
text={tag.name}
|
||||
|
||||
@@ -7,12 +7,15 @@ type TabProps = { name: string
|
||||
init?: boolean
|
||||
children: React.ReactNode }
|
||||
|
||||
type Props = { children: React.ReactNode }
|
||||
type Props = {
|
||||
children: React.ReactNode
|
||||
rightAddon?: React.ReactNode
|
||||
}
|
||||
|
||||
export const Tab = ({ children }: TabProps) => <>{children}</>
|
||||
|
||||
|
||||
const TabGroup: FC<Props> = ({ children }) => {
|
||||
const TabGroup: FC<Props> = ({ children, rightAddon }) => {
|
||||
const tabs = React.Children.toArray (children) as React.ReactElement<TabProps>[]
|
||||
|
||||
const [current, setCurrent] = useState<number> (() => {
|
||||
@@ -22,17 +25,23 @@ const TabGroup: FC<Props> = ({ children }) => {
|
||||
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<div className="flex gap-4">
|
||||
{tabs.map ((tab, i) => (
|
||||
<a key={i}
|
||||
href="#"
|
||||
className={cn (i === current && 'font-bold')}
|
||||
onClick={ev => {
|
||||
ev.preventDefault ()
|
||||
setCurrent (i)
|
||||
}}>
|
||||
{tab.props.name}
|
||||
</a>))}
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="flex min-w-0 gap-4">
|
||||
{tabs.map ((tab, i) => (
|
||||
<a key={i}
|
||||
href="#"
|
||||
className={cn (i === current && 'font-bold')}
|
||||
onClick={ev => {
|
||||
ev.preventDefault ()
|
||||
setCurrent (i)
|
||||
}}>
|
||||
{tab.props.name}
|
||||
</a>))}
|
||||
</div>
|
||||
{rightAddon && (
|
||||
<div className="shrink-0">
|
||||
{rightAddon}
|
||||
</div>)}
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
{tabs[current]}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import { DEFAULT_USER_SETTINGS, fetchUserSettings } from '@/lib/settings'
|
||||
import {
|
||||
applyClientAppearance,
|
||||
DEFAULT_USER_SETTINGS,
|
||||
fetchUserSettings,
|
||||
} from '@/lib/settings'
|
||||
|
||||
import type { Dispatch, FC, ReactNode, SetStateAction } from 'react'
|
||||
|
||||
@@ -16,29 +20,6 @@ type ContextValue = {
|
||||
const UserSettingsContext = createContext<ContextValue | null> (null)
|
||||
|
||||
|
||||
const applyTheme = (theme: UserSettings['theme']) => {
|
||||
const root = document.documentElement
|
||||
const media = window.matchMedia ('(prefers-color-scheme: dark)')
|
||||
|
||||
const sync = () => {
|
||||
const dark = theme === 'dark' || (theme === 'system' && media.matches)
|
||||
root.classList.toggle ('dark', dark)
|
||||
root.style.colorScheme = dark ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
sync ()
|
||||
|
||||
if (theme !== 'system')
|
||||
return () => { }
|
||||
|
||||
const onChange = () => sync ()
|
||||
media.addEventListener ('change', onChange)
|
||||
return () => {
|
||||
media.removeEventListener ('change', onChange)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const UserSettingsProvider: FC<{
|
||||
children: ReactNode
|
||||
user: User | null }> = ({ children, user }) => {
|
||||
@@ -87,7 +68,10 @@ export const UserSettingsProvider: FC<{
|
||||
}
|
||||
}, [user])
|
||||
|
||||
useEffect (() => applyTheme (settings.theme), [settings.theme])
|
||||
useEffect (() => {
|
||||
void settings.theme
|
||||
applyClientAppearance ()
|
||||
}, [settings.theme])
|
||||
|
||||
const value = useMemo<ContextValue> (() => ({
|
||||
error,
|
||||
|
||||
新しい課題から参照
ユーザをブロックする