Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 13 additions & 28 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,11 @@ import type { Preview } from '@storybook/nextjs-vite'
import '../styles/globals.css' // Import the global CSS file
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { initialize, mswLoader } from 'msw-storybook-addon'
import '../src/firebase' // Initialize Firebase for Storybook
import {
mockFirebaseUser,
useFirebaseUser,
} from '@/src/hooks/useFirebaseUser.mock'

const _mswApp = initialize({
initialize({
onUnhandledRequest: 'bypass',
})

const languageName = (lang: string) =>
new Intl.DisplayNames(lang, { type: 'language' }).of(lang)

const preview: Preview = {
parameters: {
controls: {
Expand All @@ -26,12 +18,6 @@ const preview: Preview = {
msw: {
handlers: [],
},
docs: {
toc: true,
},
},
beforeEach: async () => {
useFirebaseUser.mockReturnValue([mockFirebaseUser, false, undefined])
},
loaders: [mswLoader],
decorators: [
Expand All @@ -52,14 +38,14 @@ const preview: Preview = {
},
],
globalTypes: {
darkMode: {
description: 'Toggle dark mode',
defaultValue: 'dark',
theme: {
description: 'Theme for the components',
toolbar: {
icon: 'circlehollow',
icon: 'paintbrush',
items: [
{ value: 'light', right: '☀️', title: 'Light Mode' },
{ value: 'dark', right: '🌙', title: 'Dark Mode' },
{ value: 'dark', right: '🌙', title: 'Dark' }, // default
{ value: 'light', right: '☀️', title: 'Light' },
{ value: 'system', right: '🖥️', title: 'System' },
],
},
},
Expand All @@ -68,20 +54,19 @@ const preview: Preview = {
toolbar: {
icon: 'globe',
items: [
{ value: 'en', right: '🇺🇸', title: languageName('en') },
{ value: 'es', right: '🇪🇸', title: languageName('es') },
{ value: 'fr', right: '🇫🇷', title: languageName('fr') },
{ value: 'ja', right: '🇯🇵', title: languageName('ja') },
{ value: 'kr', right: '🇰🇷', title: languageName('kr') },
{ value: 'zh', right: '🇨🇳', title: languageName('zh') },
{ value: 'en', right: '🇺🇸', title: 'English' },
{ value: 'es', right: '🇪🇸', title: 'Español' },
{ value: 'fr', right: '🇫🇷', title: 'Français' },
{ value: 'ja', right: '🇯🇵', title: '日本語' },
{ value: 'kr', right: '🇰🇷', title: '한국어' },
{ value: 'zh', right: '🇨🇳', title: '中文' },
],
},
},
},
initialGlobals: {
locale: 'en',
},
tags: ['autodocs'],
}

export default preview
34 changes: 24 additions & 10 deletions components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import React from 'react'
import { FaDiscord, FaGithub } from 'react-icons/fa'
import logoBluePng from '@/src/assets/images/logo_blue.png'
import { useNextTranslation } from '@/src/hooks/i18n'
import { themeConfig } from '@/utils/themeConfig'
import { useFromUrlParam } from '../common/HOC/useFromUrl'
import LanguageSwitcher from '../common/LanguageSwitcher'
import ThemeSwitcher from '../common/ThemeSwitcher'
import ProfileDropdown from './ProfileDropdown'

interface HeaderProps {
Expand All @@ -32,9 +34,8 @@ const Header: React.FC<HeaderProps> = ({ isLoggedIn, title }) => {
return (
<Navbar
fluid
className="mx-auto p-8"
className={`mx-auto p-8 ${themeConfig.header.background}`}
style={{
backgroundColor: 'rgb(17 24 39)',
paddingLeft: 0,
paddingRight: 0,
}}
Expand All @@ -47,23 +48,35 @@ const Header: React.FC<HeaderProps> = ({ isLoggedIn, title }) => {
height={36}
className="w-6 h-6 mr-3 sm:w-9 sm:h-9 rounded-lg"
/>
<span className="self-center text-xl font-semibold text-white whitespace-nowrap">
<span
className={`self-center text-xl font-semibold whitespace-nowrap ${themeConfig.header.text}`}
>
{t('Comfy Registry')}
</span>
</Link>
<div className="flex items-center gap-2 bg-gray-900 md:order-2">
<div
className={`flex items-center gap-2 md:order-2 ${themeConfig.header.background}`}
>
{isLoggedIn ? (
<ProfileDropdown />
) : (
<>
<Button onClick={handleLogIn} color="dark" size="xs">
<span className="text-white text-xs md:text-base">
<Button
onClick={handleLogIn}
size="xs"
className={`${themeConfig.button.login} border-0`}
>
<span className="text-xs md:text-base">
{t('Login')}
</span>
</Button>

<Button onClick={handleSignUp} color="blue" size="xs">
<span className="text-xs md:text-base">
<Button
onClick={handleSignUp}
size="xs"
className={`${themeConfig.button.signup} border-0`}
>
<span className="text-xs md:text-base text-white">
{t('Signup')}
</span>
</Button>
Expand All @@ -75,10 +88,10 @@ const Header: React.FC<HeaderProps> = ({ isLoggedIn, title }) => {
? 'https://docs.comfy.org/zh-CN'
: 'https://docs.comfy.org/registry/overview'
}
color="blue"
size="xs"
className={`${themeConfig.button.documentation} border-0`}
>
<span className="text-white text-xs md:text-base">
<span className="text-xs md:text-base text-white">
{t('Documentation')}
</span>
</Button>
Expand All @@ -90,6 +103,7 @@ const Header: React.FC<HeaderProps> = ({ isLoggedIn, title }) => {
size="xs"
/>

<ThemeSwitcher />
{/* place in the most-right to reduce ... when switching language */}
<LanguageSwitcher />
</div>
Expand Down
13 changes: 13 additions & 0 deletions components/Header/ProfileDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { HiChevronDown } from 'react-icons/hi'
import { useGetUser } from '@/src/api/generated'
import { useNextTranslation } from '@/src/hooks/i18n'
import { useFirebaseUser } from '@/src/hooks/useFirebaseUser'
import { themeConfig } from '@/utils/themeConfig'
import { useLogout } from '../AuthUI/Logout'

export default function ProfileDropdown() {
Expand All @@ -13,6 +14,17 @@ export default function ProfileDropdown() {
const [onSignOut, isSignoutLoading, error] = useLogout()
const { data: user } = useGetUser()

// Custom theme for dropdown to match our theme configuration
const customDropdownTheme = {
floating: {
base: `z-10 w-fit rounded divide-y divide-gray-100 shadow focus:outline-none ${themeConfig.dropdown.background} ${themeConfig.dropdown.border}`,
content: 'py-1 text-sm',
item: {
base: `flex items-center justify-start py-2 px-4 text-sm cursor-pointer w-full ${themeConfig.dropdown.item}`,
},
},
}

// // debug
// return <>{JSON.stringify(useFirebaseUser(), null, 2)}</>
const [firebaseUser] = useFirebaseUser()
Expand All @@ -22,6 +34,7 @@ export default function ProfileDropdown() {
<Dropdown
arrowIcon={false}
inline
theme={customDropdownTheme}
label={
<div className="flex items-center gap-2">
<Avatar
Expand Down
10 changes: 5 additions & 5 deletions components/Search/SearchHit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,20 @@ const Hit: React.FC<HitProps> = ({ hit }) => {
)?.filter((e) => (e.matchedWords as string[])?.length)
return (
<Link
className="flex flex-col bg-gray-800 rounded-lg h-full dark:border-gray-700 p-4 shadow-md"
className="flex flex-col bg-gray-100 dark:bg-gray-800 rounded-lg h-full border border-gray-300 dark:border-gray-700 p-4 shadow-md"
href={`/nodes/${hit.id}`}
rel="noopener noreferrer"
>
<div className="flex flex-col flex-grow">
<h6 className="mb-2 text-base font-bold tracking-tight text-white break-words">
<h6 className="mb-2 text-base font-bold tracking-tight text-black dark:text-white break-words">
<Snippet hit={hit} attribute="name" />
</h6>

{/* description */}
<Markdown
components={{
p: ({ children }) => (
<p className="mb-1 text-xs font-light text-white mt-2 overflow-hidden text-ellipsis line-clamp-2">
<p className="mb-1 text-xs font-light text-black dark:text-white mt-2 overflow-hidden text-ellipsis line-clamp-2">
{children}
</p>
),
Expand All @@ -65,7 +65,7 @@ const Hit: React.FC<HitProps> = ({ hit }) => {

{/* nodes */}
{hit.comfy_nodes?.length && (
<div className="mb-1 text-xs font-light text-white mt-2 flex-row flex gap-2 whitespace-nowrap overflow-hidden overflow-ellipsis">
<div className="mb-1 text-xs font-light text-black dark:text-white mt-2 flex-row flex gap-2 whitespace-nowrap overflow-hidden overflow-ellipsis">
<Tooltip
content={
<pre className="max-w-[20em] max-h-[8em] overflow-auto whitespace-pre-wrap break-all">
Expand Down Expand Up @@ -99,7 +99,7 @@ const Hit: React.FC<HitProps> = ({ hit }) => {
</div>
{/* meta info */}
<p
className="text-xs font-light text-nowrap mt-2 text-gray-400"
className="text-xs font-light text-nowrap mt-2 text-gray-600 dark:text-gray-400"
dir="ltr"
>
<PublisherId publisherId={hit.publisher_id} />
Expand Down
4 changes: 2 additions & 2 deletions components/common/GenericHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ const GenericHeader: React.FC<Props> = ({
}) => {
return (
<>
<h1 className="text-xl font-bold leading-tight tracking-tight text-white sm:text-4xl">
<h1 className="text-xl font-bold leading-tight tracking-tight text-black dark:text-white sm:text-4xl">
{title}
</h1>
<p className="pt-2 pb-4 font-light text-gray-500 text-lg dark:text-gray-400">
<p className="pt-2 pb-4 font-light text-gray-700 text-lg dark:text-gray-400">
{subTitle}
</p>
<Link href={buttonLink}>
Expand Down
92 changes: 92 additions & 0 deletions components/common/ThemeSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Dropdown, DropdownItem } from 'flowbite-react'
import React from 'react'
import { HiDesktopComputer, HiMoon, HiSun } from 'react-icons/hi'
import { useNextTranslation } from '@/src/hooks/i18n'
import { Theme, useTheme } from '@/src/hooks/useTheme'

const ThemeIcon = ({
theme,
actualTheme,
}: {
theme: Theme
actualTheme: 'light' | 'dark'
}) => {
const icons = {
auto: <HiDesktopComputer className="w-4 h-4" />,
light: <HiSun className="w-4 h-4" />,
dark: <HiMoon className="w-4 h-4" />,
} satisfies Record<Theme, React.ReactNode>

if (theme in icons) {
return icons[theme]
}
throw new Error(`Unknown theme: ${theme}`)
}

export default function ThemeSwitcher() {
const { theme, actualTheme, setTheme } = useTheme()
const { t } = useNextTranslation()

const themeOptions: {
value: Theme
label: string
icon: React.ReactNode
}[] = [
{
value: 'auto',
label: t('Auto'),
icon: <HiDesktopComputer className="w-4 h-4" />,
},
{
value: 'light',
label: t('Light'),
icon: <HiSun className="w-4 h-4" />,
},
{
value: 'dark',
label: t('Dark'),
icon: <HiMoon className="w-4 h-4" />,
},
]

const currentOption = themeOptions.find((option) => option.value === theme)

// Handle double-click to toggle between light and dark themes
const handleDoubleClick = () => {
if (actualTheme === 'light') {
setTheme('dark')
} else {
setTheme('light')
}
}

return (
<Dropdown
label=""
renderTrigger={() => (
<button
type="button"
className="inline-flex items-center justify-center p-2 w-8 h-8 text-sm text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
aria-label="Toggle theme"
onDoubleClick={handleDoubleClick}
>
<ThemeIcon theme={theme} actualTheme={actualTheme} />
</button>
)}
color="gray"
size="xs"
dismissOnClick
>
{themeOptions.map((option) => (
<DropdownItem
key={option.value}
onClick={() => setTheme(option.value)}
className={`flex items-center gap-2 ${theme === option.value ? 'font-bold' : ''}`}
>
{option.icon}
{option.label}
</DropdownItem>
))}
</Dropdown>
)
}
Loading