Skip to content

Commit c80bbc5

Browse files
committed
Add components
1 parent 94a7cdf commit c80bbc5

26 files changed

+2022
-0
lines changed

src/components/Button.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Link from 'next/link'
2+
3+
export function Button({ children, ...props }) {
4+
return (
5+
<Link {...props}>
6+
<a className="inline-flex items-center bg-gray-800 hover:bg-gray-700 focus:outline-none focus:bg-gray-700 px-6 py-3 rounded-lg text-white font-medium shadow text-lg no-underline">
7+
{children}
8+
<svg viewBox="0 0 24 24" className="ml-2 h-4 w-4 fill-current text-gray-300">
9+
<path d="M18.59 13H3a1 1 0 0 1 0-2h15.59l-5.3-5.3a1 1 0 1 1 1.42-1.4l7 7a1 1 0 0 1 0 1.4l-7 7a1 1 0 0 1-1.42-1.4l5.3-5.3z" />
10+
</svg>
11+
</a>
12+
</Link>
13+
)
14+
}

src/components/ClassTable.js

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import dlv from 'dlv'
2+
import { memo } from 'react'
3+
import { defaultConfig } from '@/utils/defaultConfig'
4+
import { isObject } from '@/utils/isObject'
5+
import { castArray } from '@/utils/castArray'
6+
import clsx from 'clsx'
7+
import { Heading } from '@/components/Heading'
8+
import nameClass from 'tailwindcss/lib/util/nameClass'
9+
10+
let normalizeProperties = function (input) {
11+
if (typeof input !== 'object') return input
12+
if (Array.isArray(input)) return input.map(normalizeProperties)
13+
return Object.keys(input).reduce((newObj, key) => {
14+
let val = input[key]
15+
let newVal = typeof val === 'object' ? normalizeProperties(val) : val
16+
newObj[key.replace(/([a-z])([A-Z])/g, (m, p1, p2) => `${p1}-${p2.toLowerCase()}`)] = newVal
17+
return newObj
18+
}, {})
19+
}
20+
21+
function getUtilities(plugin) {
22+
if (!plugin) return {}
23+
const utilities = {}
24+
25+
function addUtilities(utils) {
26+
utils = Array.isArray(utils) ? utils : [utils]
27+
for (let i = 0; i < utils.length; i++) {
28+
for (let prop in utils[i]) {
29+
utilities[prop] = normalizeProperties(utils[i][prop])
30+
}
31+
}
32+
}
33+
34+
plugin()({
35+
addUtilities,
36+
addBase() {},
37+
matchUtilities: (matches, { values }) => {
38+
let modifierValues = Object.entries(values)
39+
40+
let result = Object.entries(matches).flatMap(([name, utilityFunction]) => {
41+
return modifierValues
42+
.map(([modifier, value]) => {
43+
let declarations = utilityFunction(value, {
44+
includeRules(rules) {
45+
addUtilities(rules)
46+
},
47+
})
48+
49+
if (!declarations) {
50+
return null
51+
}
52+
53+
return {
54+
[nameClass(name, modifier)]: declarations,
55+
}
56+
})
57+
.filter(Boolean)
58+
})
59+
60+
for (let obj of result) {
61+
for (let key in obj) {
62+
let deleteKey = false
63+
for (let subkey in obj[key]) {
64+
if (subkey.includes('&')) {
65+
result.push({
66+
[subkey.replace(/&/g, key)]: obj[key][subkey],
67+
})
68+
deleteKey = true
69+
}
70+
}
71+
72+
if (deleteKey) delete obj[key]
73+
}
74+
}
75+
76+
addUtilities(result)
77+
},
78+
config: () => ({
79+
mode: 'aot',
80+
future: 'all',
81+
}),
82+
theme: (path, defaultValue) => dlv(defaultConfig.theme, path, defaultValue),
83+
variants: () => [],
84+
e: (x) => x.replace(/([:.])/g, '\\$1'),
85+
corePlugins: () => true,
86+
})
87+
return utilities
88+
}
89+
90+
function stringifyProperties(
91+
properties,
92+
{ filter = () => true, transformValue = (x) => x, indent = 0 } = {}
93+
) {
94+
let lines = []
95+
Object.keys(properties).forEach((property) => {
96+
if (isObject(properties[property])) {
97+
lines.push(`${property} {`)
98+
lines.push(
99+
stringifyProperties(properties[property], { filter, transformValue, indent: indent + 1 })
100+
)
101+
lines.push('}')
102+
} else {
103+
castArray(properties[property]).forEach((value, i) => {
104+
if (!filter(property, value, properties)) return
105+
lines.push(`${' '.repeat(indent)}${property}: ${transformValue(value)};`)
106+
})
107+
}
108+
})
109+
return lines.join('\n')
110+
}
111+
112+
export const ClassTable = memo(
113+
({
114+
plugin,
115+
filterProperties,
116+
preview,
117+
sort = (x) => x,
118+
transformSelector = (x) => (x.length === 1 ? x : x.slice(1).replace(/\\/g, '')),
119+
transformProperties = ({ properties }) => properties,
120+
transformValue,
121+
custom,
122+
}) => {
123+
const utilities = {}
124+
castArray(plugin).forEach((p) => {
125+
Object.assign(utilities, getUtilities(p))
126+
})
127+
128+
return (
129+
<div className="border-b border-gray-200 overflow-hidden relative">
130+
<Heading level={2} id="class-reference" toc={true} className="relative">
131+
<span className="sr-only">Default class reference</span>
132+
</Heading>
133+
<div
134+
className={clsx(
135+
'overflow-y-auto scrollbar-w-2 scrollbar-track-gray-lighter scrollbar-thumb-rounded scrollbar-thumb-gray scrolling-touch',
136+
{ 'lg:max-h-sm': Object.keys(utilities).length > 12 }
137+
)}
138+
>
139+
{custom || (
140+
<table className="w-full text-left border-collapse">
141+
<thead>
142+
<tr>
143+
<th className="z-20 sticky top-0 text-sm font-semibold text-gray-600 bg-white p-0">
144+
<div className="pb-2 pr-2 border-b border-gray-200">Class</div>
145+
</th>
146+
<th
147+
className={clsx(
148+
'z-20 sticky top-0 text-sm font-semibold text-gray-600 bg-white p-0',
149+
{
150+
'hidden sm:table-cell': preview,
151+
}
152+
)}
153+
>
154+
<div
155+
className={clsx('pb-2 pl-2 border-b border-gray-200', { 'pr-2': preview })}
156+
>
157+
Properties
158+
</div>
159+
</th>
160+
{preview && (
161+
<th className="z-20 sticky top-0 text-sm font-semibold text-gray-600 bg-white p-0">
162+
<div className="pb-2 pl-2 border-b border-gray-200">
163+
<span className="sr-only">Preview</span>&nbsp;
164+
</div>
165+
</th>
166+
)}
167+
</tr>
168+
</thead>
169+
<tbody className="align-baseline">
170+
{sort(Object.keys(utilities)).map((utility, i) => {
171+
let selector = utility
172+
let properties = utilities[selector]
173+
174+
return (
175+
<tr key={utility}>
176+
<td
177+
translate="no"
178+
className={clsx(
179+
'py-2 pr-2 font-mono text-xs text-violet-600 whitespace-nowrap',
180+
{
181+
'border-t border-gray-200': i !== 0,
182+
}
183+
)}
184+
>
185+
{transformSelector(selector)}
186+
</td>
187+
<td
188+
translate="no"
189+
className={clsx(
190+
'py-2 pl-2 font-mono text-xs text-sky-600 whitespace-pre',
191+
{
192+
'border-t border-gray-200': i !== 0,
193+
'hidden sm:table-cell sm:pr-2': preview,
194+
}
195+
)}
196+
>
197+
{stringifyProperties(transformProperties({ selector, properties }), {
198+
filter: filterProperties,
199+
transformValue,
200+
})}
201+
</td>
202+
{preview &&
203+
preview(properties, {
204+
className: i === 0 ? '' : 'border-t border-gray-200',
205+
})}
206+
</tr>
207+
)
208+
})}
209+
</tbody>
210+
</table>
211+
)}
212+
</div>
213+
</div>
214+
)
215+
}
216+
)

src/components/Code.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
export function Token({ token, parentTypes, children }) {
2+
return <span className={`token ${token[0]}`}>{children}</span>
3+
}
4+
5+
export function Code({
6+
tokens,
7+
parentTypes = [],
8+
transformTokens = (x) => x,
9+
tokenProps = {},
10+
tokenComponent: TokenComponent = Token,
11+
}) {
12+
const tokensArr = Array.isArray(tokens) ? tokens : [tokens]
13+
14+
return tokensArr.map((token, i) => {
15+
const t = transformTokens(token, tokensArr, i)
16+
17+
if (typeof t === 'string') return t
18+
19+
if (t[0] === parentTypes[parentTypes.length - 1]) {
20+
return (
21+
<Code
22+
key={i}
23+
tokens={t[1]}
24+
parentTypes={parentTypes}
25+
tokenComponent={TokenComponent}
26+
tokenProps={tokenProps}
27+
transformTokens={transformTokens}
28+
/>
29+
)
30+
}
31+
32+
return (
33+
<TokenComponent
34+
key={i}
35+
token={t}
36+
tokenIndex={i}
37+
tokens={tokensArr}
38+
parentTypes={parentTypes}
39+
{...tokenProps}
40+
>
41+
<Code
42+
tokens={t[1]}
43+
parentTypes={[...parentTypes, t[0]]}
44+
tokenComponent={TokenComponent}
45+
tokenProps={tokenProps}
46+
transformTokens={transformTokens}
47+
/>
48+
</TokenComponent>
49+
)
50+
})
51+
}

0 commit comments

Comments
 (0)