b44ui 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.tsx +136 -34
- package/package.json +1 -1
- package/readme.md +9 -4
- package/styles.css +10 -11
package/index.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode, Children, useMemo, useState } from "react"
|
|
1
|
+
import { type ReactNode, Children, useMemo, useRef, useState } from "react"
|
|
2
2
|
import { Marked } from "marked"
|
|
3
3
|
import { markedHighlight } from "marked-highlight"
|
|
4
4
|
import hljs from "highlight.js"
|
|
@@ -6,13 +6,14 @@ import type { ClassValue } from "clsx"
|
|
|
6
6
|
import clsx from "clsx"
|
|
7
7
|
import { twMerge } from "tailwind-merge"
|
|
8
8
|
|
|
9
|
-
export type Color = 'red' | 'blue' | 'orange' | 'purple' | 'yellow'
|
|
9
|
+
export type Color = 'red' | 'blue' | 'orange' | 'purple' | 'yellow' | 'green'
|
|
10
10
|
const tintMap: Record<Color, string> = {
|
|
11
11
|
red: 'bg-red-500/20 border-red-500',
|
|
12
12
|
blue: 'bg-blue-500/20 border-blue-500',
|
|
13
13
|
orange: 'bg-orange-500/20 border-orange-500',
|
|
14
14
|
purple: 'bg-purple-500/20 border-purple-500',
|
|
15
15
|
yellow: 'bg-yellow-500/20 border-yellow-500',
|
|
16
|
+
green: 'bg-green-500/20 border-green-500',
|
|
16
17
|
}
|
|
17
18
|
const colorMap: Record<Color, string> = {
|
|
18
19
|
red: 'bg-red-600 hover:bg-red-500',
|
|
@@ -20,6 +21,7 @@ const colorMap: Record<Color, string> = {
|
|
|
20
21
|
orange: 'bg-orange-600 hover:bg-orange-500',
|
|
21
22
|
purple: 'bg-purple-600 hover:bg-purple-500',
|
|
22
23
|
yellow: 'bg-yellow-600 hover:bg-yellow-500',
|
|
24
|
+
green: 'bg-green-600 hover:bg-green-500',
|
|
23
25
|
}
|
|
24
26
|
const tintCn = (c: Color) => tintMap[c]
|
|
25
27
|
const colorCn = (c: Color) => colorMap[c]
|
|
@@ -39,12 +41,14 @@ export type DProps = {
|
|
|
39
41
|
grow?: boolean
|
|
40
42
|
gap?: number
|
|
41
43
|
p?: number
|
|
44
|
+
wd?: number
|
|
45
|
+
ht?: number
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
const dStyle = ({ gap, p, style }: DProps): React.CSSProperties | undefined => {
|
|
48
|
+
const dStyle = ({ gap, p, wd, ht, style }: DProps): React.CSSProperties | undefined => {
|
|
45
49
|
const g = sc(gap), pd = sc(p)
|
|
46
|
-
if (!g && !pd && !style) return undefined
|
|
47
|
-
return { ...(g !== undefined && { gap: g }), ...(pd !== undefined && { padding: pd }), ...style }
|
|
50
|
+
if (!g && !pd && wd === undefined && ht === undefined && !style) return undefined
|
|
51
|
+
return { ...(g !== undefined && { gap: g }), ...(pd !== undefined && { padding: pd }), ...(wd !== undefined && { width: `${wd * 100}%` }), ...(ht !== undefined && { height: `${ht * 100}%` }), ...style }
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
export const D = (props: DProps) =>
|
|
@@ -60,39 +64,57 @@ export const App = (props: DProps & { center?: boolean, width?: number }) => {
|
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
export const Centered = (props: DProps & { width?: number }) => {
|
|
63
|
-
const { children, grow, gap, p, width = 700 } = props
|
|
64
|
-
return <D cn={CN("mx-auto max-w-full px-6", rcn(props))} grow={grow} gap={gap} p={p} style={{ width }}>{children}</D>
|
|
67
|
+
const { children, grow, gap, p, wd, ht, width = 700 } = props
|
|
68
|
+
return <D cn={CN("mx-auto max-w-full px-6", rcn(props))} grow={grow} gap={gap} p={p} wd={wd} ht={ht} style={{ width }}>{children}</D>
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const TabList = (props: DProps) => {
|
|
72
|
+
const { children, grow, gap, p, wd, ht } = props
|
|
73
|
+
return <D cn={CN("flex items-end gap-4", rcn(props))} grow={grow} gap={gap} p={p} wd={wd} ht={ht}>{children}</D>
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const Tab = ({ title, active, click, grow, gap, p, ...rest }: DProps & { title: ReactNode, active?: boolean, click?: () => void } & React.ButtonHTMLAttributes<HTMLButtonElement>) => {
|
|
77
|
+
const c = rcn(rest as DProps)
|
|
78
|
+
return <button
|
|
79
|
+
className={CN("cursor-pointer border-b-2 pb-1.5 text-sm font-medium", active ? "border-zinc-100 text-zinc-100" : "border-transparent text-zinc-400 hover:text-zinc-200", grow && "flex-1", c)}
|
|
80
|
+
style={dStyle({ gap, p, wd: rest.wd, style: rest.style })}
|
|
81
|
+
onClick={click}
|
|
82
|
+
role="tab"
|
|
83
|
+
aria-selected={active}
|
|
84
|
+
{...rest}
|
|
85
|
+
>{title}</button>
|
|
65
86
|
}
|
|
66
87
|
|
|
67
88
|
export const Block = (props: DProps & { label?: ReactNode, row?: boolean, dashed?: boolean }) => {
|
|
68
|
-
const { label, children, row, dashed, grow, gap, p } = props
|
|
69
|
-
return <D cn={CN("rounded flex flex-col items-center", dashed && "border border-dashed border-zinc-700", rcn(props))} grow={grow} gap={gap ?? 4} p={p ?? 4}>
|
|
89
|
+
const { label, children, row, dashed, grow, gap, p, wd, ht } = props
|
|
90
|
+
return <D cn={CN("rounded flex flex-col items-center", dashed && "border border-dashed border-zinc-700", rcn(props))} grow={grow} gap={gap ?? 4} p={p ?? 4} wd={wd} ht={ht}>
|
|
70
91
|
{label && <span className="opacity-75">{label}</span>}
|
|
71
92
|
<div className={CN(row ? "flex-row" : "flex-col", "flex items-center")} style={{ gap: sc(gap ?? 4) }}>{children}</div>
|
|
72
93
|
</D>
|
|
73
94
|
}
|
|
74
95
|
|
|
75
96
|
export const BlockSm = (props: DProps & { dashed?: boolean }) => {
|
|
76
|
-
const { children, dashed, grow, gap, p } = props
|
|
77
|
-
return <D cn={CN("rounded text-sm", dashed && "border border-dashed border-zinc-700", rcn(props))} grow={grow} gap={gap} p={p ?? 2}
|
|
97
|
+
const { children, dashed, grow, gap, p, wd, ht } = props
|
|
98
|
+
return <D cn={CN("rounded text-sm", dashed && "border border-dashed border-zinc-700", rcn(props))} grow={grow} gap={gap} p={p ?? 2} wd={wd} ht={ht}
|
|
78
99
|
style={{ paddingLeft: sc(3), paddingRight: sc(3) }}>{children}</D>
|
|
79
100
|
}
|
|
80
101
|
|
|
81
102
|
export const Chip = (props: DProps & { click?: () => void }) => {
|
|
82
|
-
const { children, click } = props
|
|
103
|
+
const { children, click, grow, gap, p, wd, ht, style } = props
|
|
83
104
|
return <span className={CN("bg-zinc-800 rounded px-2 py-0.5 text-xs", click && "cursor-pointer hover:bg-zinc-700", rcn(props))}
|
|
105
|
+
style={dStyle({ gap, p, wd, ht, style })}
|
|
84
106
|
onClick={click}>{children}</span>
|
|
85
107
|
}
|
|
86
108
|
|
|
87
109
|
export const Card = (props: DProps) => {
|
|
88
|
-
const { children, grow, gap, p } = props
|
|
89
|
-
return <D cn={CN("rounded border border-zinc-700 bg-zinc-900", rcn(props))} grow={grow} gap={gap ?? 4} p={p ?? 4}
|
|
110
|
+
const { children, grow, gap, p, wd, ht } = props
|
|
111
|
+
return <D cn={CN("rounded border border-zinc-700 bg-zinc-900", rcn(props))} grow={grow} gap={gap ?? 4} p={p ?? 4} wd={wd} ht={ht}
|
|
90
112
|
style={{ display: 'flex', flexDirection: 'column' }}>{children}</D>
|
|
91
113
|
}
|
|
92
114
|
|
|
93
|
-
export const Col = (props: DProps) => {
|
|
94
|
-
const { children, grow, gap, p } = props
|
|
95
|
-
return <D cn={CN("flex flex-col", rcn(props))} grow={grow} gap={gap ?? 4} p={p}>{children}</D>
|
|
115
|
+
export const Col = (props: DProps & { align?: 'start' | 'center' | 'end' }) => {
|
|
116
|
+
const { children, grow, gap, p, wd, ht, align } = props
|
|
117
|
+
return <D cn={CN("flex flex-col", align === 'start' && 'items-start', align === 'center' && 'items-center', align === 'end' && 'items-end', rcn(props))} grow={grow} gap={gap ?? 4} p={p} wd={wd} ht={ht}>{children}</D>
|
|
96
118
|
}
|
|
97
119
|
|
|
98
120
|
export const Popover = (props: DProps & { text: ReactNode, color?: Color }) => {
|
|
@@ -113,7 +135,7 @@ export const Muted = (props: DProps) => {
|
|
|
113
135
|
}
|
|
114
136
|
|
|
115
137
|
export const A = ({
|
|
116
|
-
children, cn, cnIgnoreWrongUsage, grow, gap, p, style, click, href, onClick, onKeyDown, role, tabIndex, ...rest
|
|
138
|
+
children, cn, cnIgnoreWrongUsage, grow, gap, p, wd, style, click, href, onClick, onKeyDown, role, tabIndex, ...rest
|
|
117
139
|
}: DProps & { click?: () => void } & React.AnchorHTMLAttributes<HTMLAnchorElement>) => {
|
|
118
140
|
const c = rcn({ cn, cnIgnoreWrongUsage })
|
|
119
141
|
const fire = (e: React.MouseEvent<HTMLAnchorElement> | React.KeyboardEvent<HTMLAnchorElement>) => {
|
|
@@ -128,7 +150,7 @@ export const A = ({
|
|
|
128
150
|
role={buttonLike ? role ?? 'button' : role}
|
|
129
151
|
tabIndex={buttonLike ? tabIndex ?? 0 : tabIndex}
|
|
130
152
|
className={CN("inline-flex items-center gap-1 text-zinc-300 underline underline-offset-4 cursor-pointer hover:text-zinc-100", grow && "flex-1", c)}
|
|
131
|
-
style={dStyle({ gap, p, style })}
|
|
153
|
+
style={dStyle({ gap, p, wd, style })}
|
|
132
154
|
onClick={fire}
|
|
133
155
|
onKeyDown={e => {
|
|
134
156
|
if (buttonLike && (e.key === 'Enter' || e.key === ' ')) {
|
|
@@ -144,50 +166,130 @@ export const Btn = ({ children, grow, gap, p, click, color, ghost, sm, ...rest }
|
|
|
144
166
|
const c = rcn(rest as DProps)
|
|
145
167
|
return <button className={CN("rounded cursor-pointer", sm ? "px-3 py-1 text-xs" : "px-4 py-2 text-sm",
|
|
146
168
|
ghost ? "bg-transparent text-zinc-400 hover:bg-zinc-800" : color ? colorCn(color) : "bg-zinc-800 hover:bg-zinc-700", grow && "flex-1", c)}
|
|
147
|
-
style={dStyle({ gap, p })} onClick={click} {...rest}>{children}</button>
|
|
169
|
+
style={dStyle({ gap, p, wd: rest.wd, style: rest.style })} onClick={click} {...rest}>{children}</button>
|
|
148
170
|
}
|
|
149
171
|
|
|
150
172
|
export const Tint = (props: DProps & { color: Color }) => {
|
|
151
|
-
const { children, color, grow, gap, p } = props
|
|
152
|
-
return <D cn={CN("rounded text-sm", tintCn(color), rcn(props))} grow={grow} gap={gap} p={p ?? 3}>{children}</D>
|
|
173
|
+
const { children, color, grow, gap, p, wd, ht } = props
|
|
174
|
+
return <D cn={CN("rounded text-sm", tintCn(color), rcn(props))} grow={grow} gap={gap} p={p ?? 3} wd={wd} ht={ht}>{children}</D>
|
|
153
175
|
}
|
|
154
176
|
|
|
155
177
|
export const Row = (props: DProps & { ratio?: number, align?: 'mid' | 'start' | 'end' }) => {
|
|
156
|
-
const { children, ratio, align, grow, gap, p } = props
|
|
178
|
+
const { children, ratio, align, grow, gap, p, wd, ht, style } = props
|
|
157
179
|
return <div className={CN("flex items-center justify-center", align === 'mid' && "justify-between", align == 'end' && "justify-end", align == 'start' && "justify-start", grow && "flex-1", rcn(props))}
|
|
158
|
-
style={{ gap:
|
|
180
|
+
style={{ ...dStyle({ gap: gap ?? 4, p, wd, ht, style }), ...(ratio ? { width: `${ratio * 100}%` } : {}) }}>{children}</div>
|
|
159
181
|
}
|
|
160
182
|
|
|
161
183
|
export const Toolbar = (props: DProps) => {
|
|
162
|
-
const { children, gap, p } = props
|
|
163
|
-
return <Row cn={CN("border-b border-zinc-700", rcn(props))} gap={gap} p={p ?? 2} align="mid">{children}</Row>
|
|
184
|
+
const { children, gap, p, wd, ht } = props
|
|
185
|
+
return <Row cn={CN("border-b border-zinc-700", rcn(props))} gap={gap} p={p ?? 2} wd={wd} ht={ht} align="mid">{children}</Row>
|
|
164
186
|
}
|
|
165
187
|
|
|
166
188
|
export const Modal = (props: DProps & { open: boolean }) => {
|
|
167
|
-
const { children, open, gap, p } = props
|
|
189
|
+
const { children, open, gap, p, wd, ht } = props
|
|
168
190
|
return open ? <div className="fixed inset-0 flex items-center justify-center bg-black/50 z-50">
|
|
169
|
-
<Card cn={CN("max-h-[80vh] overflow-y-auto w-lg", rcn(props))} gap={gap} p={p}>{children}</Card>
|
|
191
|
+
<Card cn={CN("max-h-[80vh] overflow-y-auto w-lg", rcn(props))} gap={gap} p={p} wd={wd} ht={ht}>{children}</Card>
|
|
170
192
|
</div> : null
|
|
171
193
|
}
|
|
172
194
|
|
|
173
195
|
export const Input = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.InputHTMLAttributes<HTMLInputElement>) => {
|
|
174
196
|
const c = rcn({ cn, cnIgnoreWrongUsage })
|
|
175
|
-
return <input className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none", grow && "flex-1", c)} {...rest} />
|
|
197
|
+
return <input className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none", grow && "flex-1", c)} style={dStyle({ gap: rest.gap, p: rest.p, wd: rest.wd, style: rest.style })} {...rest} />
|
|
176
198
|
}
|
|
177
199
|
|
|
178
|
-
export const Textarea = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.TextareaHTMLAttributes<HTMLTextAreaElement>) => {
|
|
200
|
+
export const Textarea = ({ cn, cnIgnoreWrongUsage, ref, grow, ...rest }: DProps & React.TextareaHTMLAttributes<HTMLTextAreaElement> & { ref?: React.RefObject<HTMLTextAreaElement | null> }) => {
|
|
179
201
|
const c = rcn({ cn, cnIgnoreWrongUsage })
|
|
180
|
-
return <textarea className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none w-full", grow && "flex-1", c)} {...rest} />
|
|
202
|
+
return <textarea ref={ref} className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none w-full", grow && "flex-1", c)} style={dStyle({ gap: rest.gap, p: rest.p, wd: rest.wd, style: rest.style })} {...rest} />
|
|
181
203
|
}
|
|
182
204
|
|
|
183
205
|
export const Select = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.SelectHTMLAttributes<HTMLSelectElement>) => {
|
|
184
206
|
const c = rcn({ cn, cnIgnoreWrongUsage })
|
|
185
|
-
return <select className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none cursor-pointer", grow && "flex-1", c)} {...rest} />
|
|
207
|
+
return <select className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none cursor-pointer", grow && "flex-1", c)} style={dStyle({ gap: rest.gap, p: rest.p, wd: rest.wd, style: rest.style })} {...rest} />
|
|
186
208
|
}
|
|
187
209
|
|
|
188
210
|
export const Grid = (props: DProps & { cols?: number }) => {
|
|
189
|
-
const { children, cols, grow, gap, p } = props
|
|
190
|
-
return <D cn={CN("grid ui-grid", rcn(props))} grow={grow} p={p} style={{ gap: sc(gap ?? 4), '--cols': cols ?? Children.count(children) } as React.CSSProperties}>{children}</D>
|
|
211
|
+
const { children, cols, grow, gap, p, wd, ht } = props
|
|
212
|
+
return <D cn={CN("grid ui-grid", rcn(props))} grow={grow} p={p} wd={wd} ht={ht} style={{ gap: sc(gap ?? 4), '--cols': cols ?? Children.count(children) } as React.CSSProperties}>{children}</D>
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export const Hr = ({ vertical, color = 'gray', grow, gap, p, ...rest }: DProps & { vertical?: boolean, color?: Color | 'gray' }) => {
|
|
216
|
+
const c = rcn(rest as DProps)
|
|
217
|
+
const border = color === 'gray' ? "border-zinc-700" : ({
|
|
218
|
+
red: "border-red-500",
|
|
219
|
+
blue: "border-blue-500",
|
|
220
|
+
orange: "border-orange-500",
|
|
221
|
+
purple: "border-purple-500",
|
|
222
|
+
yellow: "border-yellow-500",
|
|
223
|
+
green: "border-green-500",
|
|
224
|
+
} satisfies Record<Color, string>)[color]
|
|
225
|
+
|
|
226
|
+
return <div
|
|
227
|
+
className={CN(vertical ? "self-stretch border-l" : "w-full border-t", border, grow && "flex-1", c)}
|
|
228
|
+
style={dStyle({ gap, p, wd: rest.wd, style: rest.style })}
|
|
229
|
+
aria-hidden="true"
|
|
230
|
+
/>
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export const Progress = ({ value, color = 'blue', dot, grow, gap, p, ...rest }: DProps & { value: number, color?: Color, dot?: boolean }) => {
|
|
234
|
+
const c = rcn(rest as DProps)
|
|
235
|
+
const v = Math.max(0, Math.min(1, value))
|
|
236
|
+
const fill = color === 'red' ? 'bg-red-500'
|
|
237
|
+
: color === 'orange' ? 'bg-orange-500'
|
|
238
|
+
: color === 'purple' ? 'bg-purple-500'
|
|
239
|
+
: color === 'yellow' ? 'bg-yellow-500'
|
|
240
|
+
: color === 'green' ? 'bg-green-500'
|
|
241
|
+
: 'bg-blue-500'
|
|
242
|
+
|
|
243
|
+
if (dot) return <div
|
|
244
|
+
className={CN("rounded-full border border-zinc-700 bg-zinc-800 overflow-hidden", grow && "flex-1", c)}
|
|
245
|
+
style={dStyle({ gap, p, wd: rest.wd, style: { aspectRatio: '1 / 1', ...rest.style } })}
|
|
246
|
+
>
|
|
247
|
+
<div className={CN("h-full rounded-full", fill)} style={{ opacity: v ? 1 : 0.2 }} />
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
return <div
|
|
251
|
+
className={CN("h-2 overflow-hidden rounded-full bg-zinc-800 border border-zinc-700", grow && "flex-1", c)}
|
|
252
|
+
style={dStyle({ gap, p, wd: rest.wd, style: rest.style })}
|
|
253
|
+
>
|
|
254
|
+
<div className={CN("h-full rounded-full", fill)} style={{ width: `${v * 100}%` }} />
|
|
255
|
+
</div>
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export const Dropzone = ({ children, onFiles, multiple, accept, click, ...rest }: DProps & { onFiles: (files: File[]) => void, multiple?: boolean, accept?: string, click?: () => void }) => {
|
|
259
|
+
const input = useRef<HTMLInputElement>(null)
|
|
260
|
+
const c = rcn(rest)
|
|
261
|
+
const push = (list: FileList | null) => {
|
|
262
|
+
const files = list ? Array.from(list) : []
|
|
263
|
+
if (files.length) onFiles(files)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return <div
|
|
267
|
+
className={CN("contents", c)}
|
|
268
|
+
onClick={e => {
|
|
269
|
+
click?.()
|
|
270
|
+
input.current?.click()
|
|
271
|
+
rest.onClick?.(e as any)
|
|
272
|
+
}}
|
|
273
|
+
onDragOver={e => {
|
|
274
|
+
e.preventDefault()
|
|
275
|
+
rest.onDragOver?.(e)
|
|
276
|
+
}}
|
|
277
|
+
onDrop={e => {
|
|
278
|
+
e.preventDefault()
|
|
279
|
+
push(e.dataTransfer.files)
|
|
280
|
+
rest.onDrop?.(e)
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
<input
|
|
284
|
+
ref={input}
|
|
285
|
+
hidden
|
|
286
|
+
type="file"
|
|
287
|
+
multiple={multiple}
|
|
288
|
+
accept={accept}
|
|
289
|
+
onChange={e => push(e.target.files)}
|
|
290
|
+
/>
|
|
291
|
+
{children}
|
|
292
|
+
</div>
|
|
191
293
|
}
|
|
192
294
|
|
|
193
295
|
export const Code = (props: DProps & { highlight?: string }) => {
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -28,14 +28,19 @@ export default defineConfig({
|
|
|
28
28
|
|-----------|-------|-------------|
|
|
29
29
|
| `App` | `center`, `width`, `cn` | Root layout, dark background, wraps strings in `Md` |
|
|
30
30
|
| `Centered` | `width`, `cn`, `grow` | Centered max-width container |
|
|
31
|
-
| `D` | `cn`, `style`, `grow` | Plain div with `cn` |
|
|
32
|
-
| `Row` | `align`, `ratio`, `cn`, `grow` | Flex row, `align`: `start \| mid \| end` |
|
|
33
|
-
| `Col` | `cn`, `grow` | Flex column |
|
|
31
|
+
| `D` | `cn`, `style`, `grow`, `wd` | Plain div with `cn` |
|
|
32
|
+
| `Row` | `align`, `ratio`, `cn`, `grow`, `wd` | Flex row, `align`: `start \| mid \| end` |
|
|
33
|
+
| `Col` | `cn`, `grow`, `wd` | Flex column |
|
|
34
34
|
| `Code` | `highlight` | Code block |
|
|
35
35
|
| `Grid` | `cols`, `cn`, `grow` | CSS grid, defaults to one column per child |
|
|
36
36
|
| `Card` | `cn`, `grow` | Bordered zinc-900 card |
|
|
37
37
|
| `Block` | `label`, `row`, `dashed`, `cn`, `grow` | Padded container with optional label |
|
|
38
38
|
| `BlockSm` | `dashed`, `cn`, `grow` | Smaller padded container |
|
|
39
|
+
| `TabList` | `gap`, `p`, `wd` | Simple tab row wrapper |
|
|
40
|
+
| `Tab` | `title`, `active`, `click`, `wd` | String-first tab primitive |
|
|
41
|
+
| `Hr` | `vertical`, `color`, `wd` | Horizontal or vertical divider |
|
|
42
|
+
| `Progress` | `value`, `color`, `dot`, `wd` | Progress bar or dot |
|
|
43
|
+
| `Dropzone` | `onFiles`, `multiple`, `accept` | Hidden file input wrapper for click/drop |
|
|
39
44
|
| `Btn` | `click`, `color`, `ghost`, `cn`, `grow` | Button, supports `Color` and ghost style |
|
|
40
45
|
| `A` | `href`, `click`, `cn`, `grow` | Link-styled anchor, works with `onClick` or `href` |
|
|
41
46
|
| `Chip` | `click`, `cn` | Small inline badge, clickable if `click` provided |
|
|
@@ -48,6 +53,6 @@ export default defineConfig({
|
|
|
48
53
|
| `Popover` | `text`, `color`, `cn` | Hover popover |
|
|
49
54
|
| `Md` | `className` | Markdown renderer with syntax highlighting |
|
|
50
55
|
|
|
51
|
-
`Color`: `red \| blue \| orange \| purple \| yellow`
|
|
56
|
+
`Color`: `red \| blue \| orange \| purple \| yellow \| green`
|
|
52
57
|
|
|
53
58
|
All components accept `cn` for additional Tailwind classes (merged via `tailwind-merge`).
|
package/styles.css
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
@import "highlight.js/styles/github-dark.css";
|
|
2
2
|
|
|
3
3
|
.ui-markdown { line-height: 1.5; }
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
h1, .ui-markdown h2, .ui-markdown h3 { font-weight: 700; margin: 0; }
|
|
5
|
+
h1 { font-size: 1.5em; }
|
|
6
|
+
h2 { font-size: 1.25em; }
|
|
7
|
+
h3 { font-size: 1.1em; }
|
|
8
|
+
p { margin: 0.4em 0; }
|
|
9
|
+
a { color: #93c5fd; text-decoration: underline; }
|
|
10
|
+
pre { background: #1a1a2e; border-radius: 4px; padding: 0; overflow-x: auto; margin: 0.4em 0; }
|
|
11
|
+
code { font-family: ui-monospace, monospace; font-size: 0.9em; }
|
|
12
|
+
blockquote { border-left: 3px solid #444; padding-left: 1em; opacity: 0.8; margin: 0.25em 0; }
|
|
13
|
+
img { max-width: 100%; border-radius: 6px; }
|
|
9
14
|
.ui-markdown p:first-child { margin-top: 0; }
|
|
10
15
|
.ui-markdown p:last-child { margin-bottom: 0; }
|
|
11
|
-
.ui-markdown pre { background: #1a1a2e; border-radius: 4px; padding: 0; overflow-x: auto; margin: 0.4em 0; }
|
|
12
|
-
.ui-markdown code { font-family: ui-monospace, monospace; font-size: 0.9em; }
|
|
13
16
|
.ui-markdown :not(pre) > code { background: #1a1a2e; padding: 2px 5px; border-radius: 3px; }
|
|
14
17
|
.ui-markdown ul, .ui-markdown ol { padding-left: 1.5em; margin: 0.25em 0; }
|
|
15
|
-
.ui-markdown blockquote { border-left: 3px solid #444; padding-left: 1em; opacity: 0.8; margin: 0.25em 0; }
|
|
16
|
-
.ui-markdown a { color: #93c5fd; text-decoration: underline; }
|
|
17
18
|
.ui-markdown table { border-collapse: collapse; margin: 0.4em 0; }
|
|
18
19
|
.ui-markdown th, .ui-markdown td { border: 1px solid #333; padding: 4px 10px; }
|
|
19
|
-
.ui-markdown img { max-width: 100%; border-radius: 6px; }
|
|
20
|
-
|
|
21
20
|
.ui-grid { grid-template-columns: repeat(var(--cols), 1fr); }
|
|
22
21
|
@media (max-width: 640px) { .ui-grid { grid-template-columns: 1fr; } }
|