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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy