forked from lightningpixel/modly
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.tsx
More file actions
157 lines (148 loc) · 5.62 KB
/
Copy pathindex.tsx
File metadata and controls
157 lines (148 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import React from 'react'
export function Section({ title, subtitle, children }: { title: string; subtitle: string; children: React.ReactNode }): JSX.Element {
return (
<div>
<div className="mb-7">
<h2 className="text-2xl font-bold text-zinc-100">{title}</h2>
<p className="text-sm text-zinc-500 mt-1">{subtitle}</p>
</div>
{children}
</div>
)
}
export function Card({ title, description, children }: { title?: string; description?: string; children: React.ReactNode }): JSX.Element {
return (
<div className="rounded-xl bg-surface-300 border border-zinc-800 overflow-hidden">
{(title || description) && (
<div className="px-4 py-3 border-b border-zinc-800/80">
{title && <p className="text-xs font-semibold text-zinc-200">{title}</p>}
{description && <p className="text-[11px] text-zinc-500 mt-0.5">{description}</p>}
</div>
)}
<div className="divide-y divide-zinc-800/60">
{children}
</div>
</div>
)
}
export function Row({ label, description, children }: { label: string; description?: string; children: React.ReactNode }): JSX.Element {
return (
<div className="flex items-center justify-between gap-4 px-4 py-3">
<div className="min-w-0">
<p className="text-xs font-medium text-zinc-300">{label}</p>
{description && <p className="text-[11px] text-zinc-500 mt-0.5">{description}</p>}
</div>
<div className="shrink-0">{children}</div>
</div>
)
}
export function PathRow({ label, description, value, onBrowse }: {
label: string
description?: string
value: string
onBrowse?: () => void
}): JSX.Element {
return (
<div className="px-4 py-3">
<div className="flex items-center justify-between mb-2">
<div>
<p className="text-xs font-medium text-zinc-300">{label}</p>
{description && <p className="text-[11px] text-zinc-500 mt-0.5">{description}</p>}
</div>
{onBrowse && (
<button
onClick={onBrowse}
className="px-2.5 py-1 rounded-md text-[11px] font-medium bg-zinc-800 hover:bg-zinc-700 text-zinc-300 transition-colors shrink-0 ml-4"
>
Browse…
</button>
)}
</div>
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-surface-500 border border-zinc-800">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="text-zinc-600 shrink-0">
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
</svg>
<span className="text-[11px] text-zinc-500 truncate font-mono">{value}</span>
</div>
</div>
)
}
export function InfoRow({ label, value }: { label: string; value: string }): JSX.Element {
return (
<div className="flex items-center justify-between px-4 py-3">
<p className="text-xs font-medium text-zinc-300">{label}</p>
<span className="text-xs text-zinc-500 font-mono">{value}</span>
</div>
)
}
export function Toggle({ value, onChange }: { value: boolean; onChange: (v: boolean) => void }): JSX.Element {
return (
<button
onClick={() => onChange(!value)}
className={`relative w-9 h-5 rounded-full transition-colors duration-200 shrink-0 ${value ? 'bg-accent' : 'bg-zinc-700'}`}
>
<span className={`absolute top-0.5 left-0.5 w-4 h-4 rounded-full bg-white shadow-sm transition-transform duration-200 ${value ? 'translate-x-4' : 'translate-x-0'}`} />
</button>
)
}
export function Select({ value, onChange, options }: {
value: string
onChange: (v: string) => void
options: { value: string; label: string }[]
}): JSX.Element {
return (
<select
value={value}
onChange={(e) => onChange(e.target.value)}
className="bg-zinc-800 border border-zinc-700 text-zinc-300 text-xs rounded-lg px-2.5 py-1.5 focus:outline-none focus:border-accent/50 cursor-pointer"
>
{options.map((o) => (
<option key={o.value} value={o.value}>{o.label}</option>
))}
</select>
)
}
export function SegmentedControl<T extends string>({ value, onChange, options, ariaLabel }: {
value: T
onChange: (v: T) => void
options: { value: T; label: string }[]
ariaLabel?: string
}): JSX.Element {
return (
<div role="group" aria-label={ariaLabel} className="inline-flex p-0.5 rounded-lg bg-zinc-800 border border-zinc-700">
{options.map((o) => {
const active = o.value === value
return (
<button
key={o.value}
type="button"
aria-pressed={active}
onClick={() => onChange(o.value)}
className={`px-3 py-1 rounded-md text-xs font-medium transition-colors ${
active
? 'bg-accent/20 text-accent-light'
: 'text-zinc-400 hover:text-zinc-200'
}`}
>
{o.label}
</button>
)
})}
</div>
)
}
export function LinkButton({ label, href }: { label: string; href?: string }): JSX.Element {
const handleClick = (): void => {
if (href) window.open(href, '_blank')
}
return (
<button onClick={handleClick} className="flex items-center gap-1 px-2.5 py-1.5 rounded-lg text-xs font-medium bg-zinc-800 hover:bg-zinc-700 text-zinc-300 transition-colors">
{label}
<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="text-zinc-500">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
<polyline points="15 3 21 3 21 9" />
<line x1="10" y1="14" x2="21" y2="3" />
</svg>
</button>
)
}