Skip to content
Clone

refactor: update input and select class names for consistency across components

ZhenYi committed
parent 29b68f7 commit 6ee2d8b Browse files

16 files changed

+93 −43

File tree 16
Modified view/app/src/components/alert.tsx View view/app/src/components/alert.tsx
@@ -3,9 +3,9 @@
33export type AlertTone = 'error' | 'success' | 'info'
44
55const toneClasses: Record<AlertTone, string> = {
6 error: 'bg-error text-error-foreground',
7 success: 'bg-success text-success-foreground',
8 info: 'bg-info text-info-foreground',
6 error: 'alert alert-error',
7 success: 'alert alert-success',
8 info: 'alert alert-info',
99}
1010
1111export interface AlertProps {
Modified view/app/src/domains/repo/settings/ui/sections/archives-settings.tsx View view/app/src/domains/repo/settings/ui/sections/archives-settings.tsx
@@ -10,7 +10,7 @@
1010import { formatBytes } from '@app/lib'
1111import { Button } from '@app/ui'
1212import { useState } from 'react'
13import { Fact, Field, inputCls, Notice, SectionHead } from '../parts'
13import { Fact, Field, inputCls, Notice, SectionHead, selectCls } from '../parts'
1414import { useAction } from '../use-action'
1515
1616const FORMATS: Array<{ value: ArchiveFormat; get label(): string }> = [
@@ -120,7 +120,7 @@
120120 />
121121 </Field>
122122 <Field label={t('repo.archives.format')}>
123 <select className={inputCls} value={format} onChange={(e) => setFormat(e.target.value as ArchiveFormat)}>
123 <select className={selectCls} value={format} onChange={(e) => setFormat(e.target.value as ArchiveFormat)}>
124124 {FORMATS.map((item) => (
125125 <option key={item.value} value={item.value}>
126126 {item.label}
Modified view/app/src/domains/repo/settings/ui/parts.tsx View view/app/src/domains/repo/settings/ui/parts.tsx
@@ -5,9 +5,11 @@
55
66export const fieldLabel = 'mb-2 block text-[13px] font-medium text-shell-ink'
77export const inputCls =
8 'repo-settings-input h-11 w-full max-w-[520px] rounded-lg border border-shell-hairline bg-shell-field px-3 text-[13.5px] outline-none transition-colors focus:border-shell-tile'
8 'input repo-settings-input h-11 w-full max-w-[520px] rounded-lg border-shell-hairline bg-shell-field px-3 text-[13.5px] outline-none transition-colors focus:border-shell-tile'
9export const selectCls =
10 'select repo-settings-input h-11 w-full max-w-[520px] rounded-lg border-shell-hairline bg-shell-field px-3 text-[13.5px] outline-none transition-colors focus:border-shell-tile'
911export const areaCls =
10 'repo-settings-input w-full max-w-[520px] resize-y rounded-lg border border-shell-hairline bg-shell-field px-3 py-3 text-[13.5px] leading-6 outline-none transition-colors focus:border-shell-tile'
12 'textarea repo-settings-input w-full max-w-[520px] resize-y rounded-lg border-shell-hairline bg-shell-field px-3 py-3 text-[13.5px] leading-6 outline-none transition-colors focus:border-shell-tile'
1113
1214export function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) {
1315 return (
Modified view/app/src/domains/session/ui/chip.tsx View view/app/src/domains/session/ui/chip.tsx
@@ -8,7 +8,9 @@
88/** Small muted pill used for email addresses, purpose tags and token states. */
99export function Chip({ children, className = '' }: ChipProps) {
1010 return (
11 <span className={`inline-flex items-center gap-1.5 rounded-lg bg-muted px-3 py-1.5 ${className}`}>{children}</span>
11 <span className={`badge inline-flex items-center gap-1.5 rounded-lg bg-muted px-3 py-1.5 ${className}`}>
12 {children}
13 </span>
1214 )
1315}
1416
@@ -19,7 +21,7 @@
1921/** Tighter uppercase mono tag next to an address chip. */
2022export function Pill({ children }: PillProps) {
2123 return (
22 <span className="inline-flex items-center rounded-md bg-muted px-2.5 py-1 font-mono text-[9.5px] font-bold tracking-[1px] text-muted-foreground uppercase">
24 <span className="badge inline-flex items-center rounded-md bg-muted px-2.5 py-1 font-mono text-[9.5px] font-bold tracking-[1px] text-muted-foreground uppercase">
2325 {children}
2426 </span>
2527 )
Modified view/app/src/domains/settings/ui/sections/account-section.tsx View view/app/src/domains/settings/ui/sections/account-section.tsx
@@ -1,5 +1,5 @@
11import { LanguagePicker } from '@app/components'
2import { CopyButton, Field, fmtDate, inputCls, SaveBar, SectionTitle, useSave } from '@app/domains/shared'
2import { CopyButton, Field, fmtDate, inputCls, SaveBar, SectionTitle, selectCls, useSave } from '@app/domains/shared'
33import { type Locale, useT } from '@app/i18n'
44import { Button } from '@app/ui'
55import { useRef, useState } from 'react'
@@ -86,7 +86,7 @@
8686 <div className="grid max-w-[700px] gap-3 sm:grid-cols-3">
8787 <Field label={t('settings.account.language')}>
8888 <LanguagePicker
89 className={`${inputCls} max-w-none`}
89 className={`${selectCls} max-w-none`}
9090 value={language}
9191 onChange={(next: Locale | null) => setLanguage(next ?? '')}
9292 />
Modified view/app/src/domains/settings/ui/sections/appearance-section.tsx View view/app/src/domains/settings/ui/sections/appearance-section.tsx
@@ -1,5 +1,5 @@
11import { normalizeBoardView } from '@app/domains/issues/model'
2import { Busy, Field, inputCls, SaveBar, SectionTitle, useSave } from '@app/domains/shared'
2import { Busy, Field, SaveBar, SectionTitle, selectCls, useSave } from '@app/domains/shared'
33import { type MessageKey, useT } from '@app/i18n'
44import { previewColors, setTheme } from '@app/lib'
55import { useThemeContext } from '@app/providers'
@@ -185,7 +185,7 @@
185185 <PalettePicker />
186186 <Field label={t('settings.appearance.themeMode')}>
187187 <select
188 className={inputCls}
188 className={selectCls}
189189 value={current.theme}
190190 onChange={(e) => {
191191 applyMode(e.target.value)
@@ -202,7 +202,7 @@
202202 hint={`${t(option.noteKey)} · ${t('settings.appearance.diffHintSuffix')}`}
203203 >
204204 <select
205 className={inputCls}
205 className={selectCls}
206206 value={current.diff}
207207 onChange={(e) => setForm({ ...current, diff: e.target.value })}
208208 >
@@ -218,7 +218,7 @@
218218 </div>
219219 <Field label={t('settings.appearance.boardView')} hint={t('settings.appearance.boardViewHint')}>
220220 <select
221 className={inputCls}
221 className={selectCls}
222222 value={current.boardView}
223223 onChange={(e) => setForm({ ...current, boardView: e.target.value })}
224224 >
Modified view/app/src/domains/settings/ui/sections/privacy-section.tsx View view/app/src/domains/settings/ui/sections/privacy-section.tsx
@@ -1,4 +1,4 @@
1import { Busy, Field, inputCls, SaveBar, SectionTitle, Toggle, useSave } from '@app/domains/shared'
1import { Busy, Field, SaveBar, SectionTitle, selectCls, Toggle, useSave } from '@app/domains/shared'
22import { useT } from '@app/i18n'
33import { useState } from 'react'
44import * as api from '../../model/api'
@@ -38,7 +38,11 @@
3838 <section>
3939 <SectionTitle title={t('settings.privacy.title')} sub={t('settings.privacy.sub')} />
4040 <Field label={t('userSettings.privacy.dms')}>
41 <select className={inputCls} value={current.dms} onChange={(e) => setForm({ ...current, dms: e.target.value })}>
41 <select
42 className={selectCls}
43 value={current.dms}
44 onChange={(e) => setForm({ ...current, dms: e.target.value })}
45 >
4246 {AUDIENCE_VALUES.map((value) => (
4347 <option key={value} value={value}>
4448 {t(AUDIENCE_KEYS[value])}
@@ -48,7 +52,7 @@
4852 </Field>
4953 <Field label={t('userSettings.privacy.mentions')}>
5054 <select
51 className={inputCls}
55 className={selectCls}
5256 value={current.mentions}
5357 onChange={(e) => setForm({ ...current, mentions: e.target.value })}
5458 >
Modified view/app/src/domains/settings/ui/sections/profile-section.tsx View view/app/src/domains/settings/ui/sections/profile-section.tsx
@@ -1,4 +1,4 @@
1import { Field, inputCls, SaveBar, SectionTitle, Toggle, useSave } from '@app/domains/shared'
1import { Field, inputCls, SaveBar, SectionTitle, selectCls, textareaCls, Toggle, useSave } from '@app/domains/shared'
22import { type MessageKey, useT } from '@app/i18n'
33import type { ProfileVisibility } from '@app/services/api'
44import { useState } from 'react'
@@ -38,7 +38,7 @@
3838 <SectionTitle title={t('settings.profile.title')} sub={t('settings.profile.sub')} />
3939 <Field label={t('userSettings.profile.bio')}>
4040 <textarea
41 className="w-full max-w-[560px] resize-none rounded-md border border-shell-hairline bg-shell-field px-3 py-2 text-[13.5px] outline-none"
41 className={`${textareaCls} max-w-[560px] resize-none`}
4242 rows={3}
4343 maxLength={500}
4444 value={form.bio}
@@ -92,7 +92,7 @@
9292 </div>
9393 <Field label={t('userSettings.profile.visibility')}>
9494 <select
95 className={inputCls}
95 className={selectCls}
9696 value={form.visibility}
9797 onChange={(e) => set('visibility', e.target.value as ProfileVisibility)}
9898 >
Modified view/app/src/domains/shared/settings-utils.ts View view/app/src/domains/shared/settings-utils.ts
@@ -14,7 +14,11 @@
1414 * focus ring, so this only carries layout and type.
1515 */
1616export const inputCls =
17 'h-10 w-full max-w-[440px] rounded-md border border-shell-hairline bg-shell-field px-3 text-[13.5px] text-shell-ink outline-none transition-colors'
17 'input h-10 w-full max-w-[440px] rounded-md border-shell-hairline bg-shell-field px-3 text-[13.5px] text-shell-ink'
18export const selectCls =
19 'select h-10 w-full max-w-[440px] rounded-md border-shell-hairline bg-shell-field px-3 text-[13.5px] text-shell-ink'
20export const textareaCls =
21 'textarea w-full max-w-[440px] rounded-md border-shell-hairline bg-shell-field px-3 py-2 text-[13.5px] text-shell-ink'
1822
1923/**
2024 * `ApiFailure` carries the server's own wording; a plain Error thrown by a
Modified view/app/src/domains/space/management/ui/space-settings/danger-section.tsx View view/app/src/domains/space/management/ui/space-settings/danger-section.tsx
@@ -31,7 +31,7 @@
3131 {t('space.danger.description', { count: space.members_count })}
3232 </p>
3333 {!armed ? (
34 <Button className="settings-danger-btn mt-4 h-9" disabled={busy} onClick={() => setArmed(true)}>
34 <Button variant="danger" className="mt-4 h-9" disabled={busy} onClick={() => setArmed(true)}>
3535 {t('space.settings.deleteSpace')}
3636 </Button>
3737 ) : (
@@ -46,7 +46,8 @@
4646 </Field>
4747 <div className="flex flex-wrap items-center gap-3">
4848 <Button
49 className="settings-danger-btn h-9"
49 variant="danger"
50 className="h-9"
5051 disabled={busy || confirm.trim().toLowerCase() !== spaceName.toLowerCase()}
5152 onClick={() => void run(() => deleteSpace(spaceName).then(onDeleted))}
5253 >
Modified view/app/src/domains/space/management/ui/space-settings/general-section.tsx View view/app/src/domains/space/management/ui/space-settings/general-section.tsx
@@ -1,5 +1,16 @@
11import { Alert } from '@app/components'
2import { CopyButton, Field, fmtDate, inputCls, SaveBar, SectionTitle, Toggle, useSave } from '@app/domains/shared'
2import {
3 CopyButton,
4 Field,
5 fmtDate,
6 inputCls,
7 SaveBar,
8 SectionTitle,
9 selectCls,
10 textareaCls,
11 Toggle,
12 useSave,
13} from '@app/domains/shared'
314import { useT } from '@app/i18n'
415import { useState } from 'react'
516import { updateSpace } from '../../model/api'
@@ -71,7 +82,7 @@
7182 </Field>
7283 <Field label={t('space.general.description')} hint={t('space.general.descriptionHint')}>
7384 <textarea
74 className={`${inputCls} h-auto resize-none py-2 leading-relaxed`}
85 className={`${textareaCls} h-auto resize-none leading-relaxed`}
7586 rows={3}
7687 maxLength={512}
7788 disabled={!isOwner}
@@ -81,7 +92,7 @@
8192 </Field>
8293 <Field label={t('space.general.welcome')} hint={t('space.general.welcomeHint')}>
8394 <textarea
84 className={`${inputCls} h-auto resize-none py-2 leading-relaxed`}
95 className={`${textareaCls} h-auto resize-none leading-relaxed`}
8596 rows={2}
8697 maxLength={512}
8798 disabled={!isOwner}
@@ -106,7 +117,7 @@
106117 />
107118 <Field label={t('space.general.joinLevel')}>
108119 <select
109 className={inputCls}
120 className={selectCls}
110121 disabled={!isOwner || !draft.allow_join}
111122 value={draft.allow_join_level}
112123 onChange={(e) => set('allow_join_level', e.target.value)}
Modified view/app/src/domains/space/management/ui/space-settings/join-rules-section.tsx View view/app/src/domains/space/management/ui/space-settings/join-rules-section.tsx
@@ -6,6 +6,7 @@
66 fmtDate,
77 inputCls,
88 SectionTitle,
9 selectCls,
910 SettingRow,
1011 Toggle,
1112 useSave,
@@ -54,7 +55,7 @@
5455 <div className="grid gap-x-4 sm:grid-cols-3">
5556 <Field label={t('space.joinRules.grantRole')}>
5657 <select
57 className={inputCls}
58 className={selectCls}
5859 value={draft.role_id}
5960 onChange={(e) => setDraft({ ...draft, role_id: e.target.value })}
6061 >
@@ -68,7 +69,7 @@
6869 </Field>
6970 <Field label={t('space.joinRules.trigger')}>
7071 <select
71 className={inputCls}
72 className={selectCls}
7273 value={draft.trigger}
7374 onChange={(e) => setDraft({ ...draft, trigger: e.target.value })}
7475 >
Modified view/app/src/domains/space/management/ui/space-settings/my-membership-section.tsx View view/app/src/domains/space/management/ui/space-settings/my-membership-section.tsx
@@ -1,4 +1,4 @@
1import { Busy, Field, fmtDate, inputCls, SaveBar, SectionTitle, Toggle, useSave } from '@app/domains/shared'
1import { Busy, Field, fmtDate, inputCls, SaveBar, SectionTitle, selectCls, Toggle, useSave } from '@app/domains/shared'
22import { useT } from '@app/i18n'
33import { spaceAdminKey, useAsync } from '@app/lib'
44import { useState } from 'react'
@@ -71,7 +71,7 @@
7171 </Field>
7272 <Field label={t('space.alerts.label')}>
7373 <select
74 className={inputCls}
74 className={selectCls}
7575 value={draft.message_notifications}
7676 onChange={(e) => set('message_notifications', e.target.value as Draft['message_notifications'])}
7777 >
Modified view/app/src/tokens/primitive.css View view/app/src/tokens/primitive.css
@@ -10,7 +10,7 @@
1010 --primary-foreground: #111111;
1111 --secondary: #e7e8e5;
1212 --secondary-foreground: #111111;
13 --border: #cbccc9;
13 --border-color: #cbccc9;
1414 --input: #cbccc9;
1515 --ring: #666666;
1616 --destructive: #d93c15;
@@ -61,7 +61,7 @@
6161 --muted-foreground: #b8b9b6;
6262 --secondary: #2e2e2e;
6363 --secondary-foreground: #ffffff;
64 --border: #2e2e2e;
64 --border-color: #2e2e2e;
6565 --input: #2e2e2e;
6666 --destructive: #ff5c33;
6767 --success: #222924;
@@ -73,3 +73,28 @@
7373 --info: #222229;
7474 --info-foreground: #b2b2ff;
7575}
76
77/* daisyUI runtime tokens, mapped onto the application palette. */
78:root {
79 --color-base-100: var(--card);
80 --color-base-200: var(--muted);
81 --color-base-300: var(--border-color);
82 --color-base-content: var(--foreground);
83 --color-primary-content: var(--primary-foreground);
84 --color-secondary-content: var(--secondary-foreground);
85 --color-accent: var(--primary);
86 --color-accent-content: var(--primary-foreground);
87 --color-neutral: var(--foreground);
88 --color-neutral-content: var(--card);
89 --color-success-content: var(--success-foreground);
90 --color-warning-content: var(--warning-foreground);
91 --color-error-content: var(--error-foreground);
92 --color-info-content: var(--info-foreground);
93 --radius-selector: 5px;
94 --radius-box: 16px;
95 --size-selector: 0.25rem;
96 --size-field: 0.25rem;
97 --border: 1px;
98 --depth: 0;
99 --noise: 0;
100}
Modified view/app/src/tokens/semantic.css View view/app/src/tokens/semantic.css
@@ -8,7 +8,7 @@
88 --color-primary-foreground: var(--primary-foreground);
99 --color-secondary: var(--secondary);
1010 --color-secondary-foreground: var(--secondary-foreground);
11 --color-border: var(--border);
11 --color-border: var(--border-color);
1212 --color-input: var(--input);
1313 --color-ring: var(--ring);
1414 --color-destructive: var(--destructive);
Modified view/app/src/ui/button.tsx View view/app/src/ui/button.tsx
@@ -1,6 +1,6 @@
11import { type ButtonHTMLAttributes, forwardRef } from 'react'
22
3export type ButtonVariant = 'primary' | 'secondary' | 'ghost'
3export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger'
44export type ButtonSize = 'default' | 'lg'
55
66export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
@@ -9,15 +9,15 @@
99}
1010
1111const variantClasses: Record<ButtonVariant, string> = {
12 primary:
13 'bg-primary text-primary-foreground font-mono font-bold tracking-[0.4px] hover:brightness-95 active:brightness-90',
14 secondary: 'border border-border bg-card text-foreground font-sans font-medium hover:bg-muted',
15 ghost: 'bg-transparent text-foreground hover:bg-muted',
12 primary: 'btn btn-primary font-mono font-bold tracking-[0.4px]',
13 secondary: 'btn btn-outline border-border bg-card text-foreground font-sans font-medium hover:bg-muted',
14 ghost: 'btn btn-ghost text-foreground',
15 danger: 'btn btn-error bg-[#f23f43] text-white hover:bg-[#d9363a]',
1616}
1717
1818const sizeClasses: Record<ButtonSize, string> = {
19 default: 'h-9 gap-2 rounded-field px-4 text-sm',
20 lg: 'h-12 gap-[9px] rounded-field px-6 text-sm',
19 default: 'btn-sm h-9 gap-2 rounded-field px-4 text-sm',
20 lg: 'btn-lg h-12 gap-[9px] rounded-field px-6 text-sm',
2121}
2222
2323/** Business-free UI kit primitive: no domain logic, no store, no requests. */
@@ -29,7 +29,7 @@
2929 <button
3030 ref={ref}
3131 type={type}
32 className={`inline-flex items-center justify-center transition-[filter,background-color] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}
32 className={`${variantClasses[variant]} ${sizeClasses[size]} transition-[filter,background-color] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 ${className}`}
3333 {...props}
3434 />
3535 )