Skip to content

Commit fffaa22

Browse files
Copilotsnomiaoclaude
authored
Fix create-publisher modal background to use dark theme (#178)
* Initial plan * Fix create-publisher modal background colors to use dark theme Co-authored-by: snomiao <[email protected]> * Add Storybook story for CreatePublisherModal to demonstrate fix Co-authored-by: snomiao <[email protected]> * fix: Update Storybook import to use nextjs-vite package - Change import from @storybook/react to @storybook/nextjs-vite - Resolves linting error about direct renderer package imports * fix: Correct prop name in CreatePublisherModal stories - Change openModal to open to match component props - Fixes TypeScript build error * fix: Disable husky in CI auto-commit step - Set HUSKY=0 environment variable to prevent pre-commit hooks - Fixes lint-staged empty commit error in CI * format: Apply prettier --fix changes * refactor: Extract CreatePublisherFormContent component - Create new reusable CreatePublisherFormContent component - Contains form logic and UI for creating a publisher - Accepts onSuccess and onCancel callbacks for flexibility * refactor: Update CreatePublisherModal to use CreatePublisherFormContent - Remove duplicate form logic and state management - Use extracted CreatePublisherFormContent component - Simplify modal to only handle modal-specific concerns - Fixes duplicate title issue * refactor: Update create publisher page to use CreatePublisherFormContent - Remove duplicate form logic and state management - Use extracted CreatePublisherFormContent component - Simplify page to only handle page-specific concerns (breadcrumb, routing) * fix: Correct import path in CreatePublisherModal stories Update import to use relative path since story file is now co-located with the component in components/publisher/ directory after Storybook restructure. * format: Apply prettier --fix changes * feat: Add Storybook story for create publisher page - Create CreatePublisherPageLayout component for Storybook - Demonstrates the full create publisher page UI - Located at components/pages/create.stories.tsx as requested - Includes breadcrumb navigation and form content Addresses review comment on PR #178 * feat: Add title heading to create publisher page - Add showTitle prop to CreatePublisherFormContent component - Display "Create Publisher" heading when showTitle is enabled - Enable title display on the create publisher page - Update Storybook story to show title Addresses review comment requesting addition of page title. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: snomiao <[email protected]> Co-authored-by: snomiao <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent fe23714 commit fffaa22

File tree

6 files changed

+299
-278
lines changed

6 files changed

+299
-278
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Meta, StoryObj } from '@storybook/nextjs-vite'
2+
import { Breadcrumb, Card } from 'flowbite-react'
3+
import { HiHome } from 'react-icons/hi'
4+
import CreatePublisherFormContent from '@/components/publisher/CreatePublisherFormContent'
5+
6+
const CreatePublisherPageLayout = () => {
7+
const handleSuccess = (username: string) => {
8+
console.log('Publisher created successfully:', username)
9+
// In a real scenario, this would navigate to the publisher page
10+
}
11+
12+
const handleCancel = () => {
13+
console.log('Create publisher cancelled')
14+
// In a real scenario, this would navigate back
15+
}
16+
17+
return (
18+
<div className="p-4 bg-gray-900 min-h-screen">
19+
<div className="py-4">
20+
<Breadcrumb>
21+
<Breadcrumb.Item
22+
href="/"
23+
icon={HiHome}
24+
onClick={(e) => {
25+
e.preventDefault()
26+
console.log('Navigate to home')
27+
}}
28+
className="dark"
29+
>
30+
Home
31+
</Breadcrumb.Item>
32+
<Breadcrumb.Item className="dark">
33+
Create Publisher
34+
</Breadcrumb.Item>
35+
</Breadcrumb>
36+
</div>
37+
38+
<section className="p-0">
39+
<div className="flex items-center justify-center px-0 py-4 mx-auto">
40+
<div className="w-full mx-auto shadow sm:max-w-lg">
41+
<Card className="p-2 bg-gray-800 border border-gray-700 md:p-6 rounded-2xl">
42+
<CreatePublisherFormContent
43+
onSuccess={handleSuccess}
44+
onCancel={handleCancel}
45+
showTitle={true}
46+
/>
47+
</Card>
48+
</div>
49+
</div>
50+
</section>
51+
</div>
52+
)
53+
}
54+
55+
const meta: Meta<typeof CreatePublisherPageLayout> = {
56+
title: 'Pages/Publishers/CreatePublisherPage',
57+
component: CreatePublisherPageLayout,
58+
parameters: {
59+
layout: 'fullscreen',
60+
},
61+
}
62+
63+
export default meta
64+
type Story = StoryObj<typeof CreatePublisherPageLayout>
65+
66+
export const Default: Story = {}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { isAxiosError } from 'axios'
2+
import { Button, TextInput } from 'flowbite-react'
3+
import { useRouter } from 'next/router'
4+
import React, { useState } from 'react'
5+
import { toast } from 'react-toastify'
6+
import { useNextTranslation } from 'src/hooks/i18n'
7+
import { customThemeTextInput } from 'utils/comfyTheme'
8+
import { useCreatePublisher, useValidatePublisher } from '@/src/api/generated'
9+
10+
type CreatePublisherFormContentProps = {
11+
onSuccess?: (username: string) => void
12+
onCancel?: () => void
13+
showTitle?: boolean
14+
}
15+
16+
const CreatePublisherFormContent: React.FC<CreatePublisherFormContentProps> = ({
17+
onSuccess,
18+
onCancel,
19+
showTitle = false,
20+
}) => {
21+
const { t } = useNextTranslation()
22+
const router = useRouter()
23+
const [username, setUsername] = useState('')
24+
const [displayName, setDisplayName] = useState('')
25+
const [publisherValidationError, setPublisherValidationError] = useState('')
26+
27+
const {
28+
data,
29+
isLoading: isLoadingValidation,
30+
error,
31+
} = useValidatePublisher({
32+
username: username,
33+
})
34+
const createPublisherMutation = useCreatePublisher()
35+
36+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
37+
event.preventDefault()
38+
createPublisherMutation.mutate(
39+
{
40+
data: {
41+
id: username,
42+
name: displayName,
43+
},
44+
},
45+
{
46+
onError: (error) => {
47+
toast.error(
48+
t('Could not create publisher. Please try again.')
49+
)
50+
},
51+
onSuccess: () => {
52+
toast.success('Publisher created successfully!')
53+
if (onSuccess) {
54+
onSuccess(username)
55+
} else {
56+
router.push(`/publishers/${username}`)
57+
}
58+
},
59+
}
60+
)
61+
}
62+
63+
React.useEffect(() => {
64+
if (isAxiosError(error)) {
65+
setPublisherValidationError(error.response?.data?.message)
66+
} else {
67+
setPublisherValidationError('')
68+
}
69+
}, [error])
70+
71+
return (
72+
<>
73+
{showTitle && (
74+
<h2 className="text-2xl font-bold text-white mb-4">
75+
{t('Create Publisher')}
76+
</h2>
77+
)}
78+
<p className="flex justify-center text-sm font-medium text-gray-400 ">
79+
{t(
80+
'Register a publisher to begin distributing custom nodes on Comfy.'
81+
)}
82+
</p>
83+
84+
<form
85+
className="mt-4 space-y-4 lg:space-y-6"
86+
onSubmit={handleSubmit}
87+
>
88+
<div>
89+
<label className="block mb-1 text-xs font-bold text-white">
90+
{t('Username')}
91+
</label>
92+
<TextInput
93+
id="name"
94+
placeholder={t('E.g. janedoe55')}
95+
required
96+
theme={customThemeTextInput}
97+
type="text"
98+
sizing="sm"
99+
value={username}
100+
onChange={(e) => setUsername(e.target.value)}
101+
color={
102+
!isLoadingValidation && publisherValidationError
103+
? 'failure'
104+
: 'success'
105+
}
106+
helperText={
107+
<>
108+
{isLoadingValidation && (
109+
<>{t('Checking username...')}</>
110+
)}
111+
{!isLoadingValidation &&
112+
publisherValidationError && (
113+
<>
114+
<span className="font-medium"></span>{' '}
115+
{publisherValidationError}
116+
</>
117+
)}
118+
</>
119+
}
120+
/>
121+
</div>
122+
<div>
123+
<label className="block mb-1 text-xs font-bold text-white">
124+
{t('Display Name')}
125+
</label>
126+
<TextInput
127+
sizing="sm"
128+
theme={customThemeTextInput}
129+
id="displayName"
130+
className="border-gray-700 "
131+
placeholder={t('E.g. Jane Doe')}
132+
required
133+
type="text"
134+
value={displayName}
135+
onChange={(e) => setDisplayName(e.target.value)}
136+
/>
137+
</div>
138+
139+
<div className="flex center gap-4">
140+
<Button
141+
type="button"
142+
onClick={onCancel}
143+
color="light"
144+
className=" bg-gray-900"
145+
>
146+
<span className="text-white">{t('Cancel')}</span>
147+
</Button>
148+
<Button
149+
type="submit"
150+
color="blue"
151+
size="sm"
152+
disabled={
153+
isLoadingValidation || !!publisherValidationError
154+
}
155+
>
156+
{t('Create')}
157+
</Button>
158+
</div>
159+
</form>
160+
</>
161+
)
162+
}
163+
164+
export default CreatePublisherFormContent
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
2+
import CreatePublisherModal from './CreatePublisherModal'
3+
4+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
5+
const meta: Meta<typeof CreatePublisherModal> = {
6+
title: 'Components/Publisher/CreatePublisherModal',
7+
component: CreatePublisherModal,
8+
parameters: {
9+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
10+
layout: 'centered',
11+
},
12+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
13+
tags: ['autodocs'],
14+
// More on argTypes: https://storybook.js.org/docs/api/argtypes
15+
argTypes: {
16+
open: { control: 'boolean' },
17+
onCloseModal: { action: 'onCloseModal' },
18+
onSuccess: { action: 'onSuccess' },
19+
},
20+
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
21+
args: {
22+
open: true,
23+
onCloseModal: () => {},
24+
},
25+
}
26+
27+
export default meta
28+
type Story = StoryObj<typeof meta>
29+
30+
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
31+
export const Default: Story = {
32+
args: {
33+
open: true,
34+
},
35+
}
36+
37+
export const Closed: Story = {
38+
args: {
39+
open: false,
40+
},
41+
}

0 commit comments

Comments
 (0)