Skip to content

Commit

Permalink
Merge pull request #428 from omnifed/427-docs-fix-copy-paste-code-button
Browse files Browse the repository at this point in the history
427 docs fix copy paste code button
  • Loading branch information
caseybaggz committed Sep 3, 2024
2 parents e428a22 + 5b6e1f8 commit 1d7a78e
Show file tree
Hide file tree
Showing 23 changed files with 774 additions and 85 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"Checkmark",
"csstools",
"frontmatter",
"hljs",
"Killa",
"nextjs",
"omni",
Expand Down
1 change: 1 addition & 0 deletions docs/app/components/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export function TabPageContentSections(
<div
className={grid({
columns: 12,
position: 'relative',
})}
>
{props.children}
Expand Down
103 changes: 103 additions & 0 deletions docs/app/components/code-builder/builder-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
'use client'

import { vstack } from '@cerberus/styled-system/patterns'
import type {
BooleanResult,
BuilderResult,
EnumResult,
TextResult,
} from './helpers'
import { Field, Label, Show } from '@cerberus-design/react'
import { lazy, useCallback, type ChangeEvent } from 'react'
import { useCodeBuilder } from '@/app/context/code-builder'
import { css } from '@cerberus/styled-system/css'

const Select = lazy(() => import('./builder-select'))
const Input = lazy(() => import('./builder-input'))
const Toggle = lazy(() => import('./builder-toggle'))

interface BuilderFormProps {
api: Record<string, BuilderResult>
}

export default function BuilderForm(props: BuilderFormProps) {
const { selectedProps, setSelectedProps } = useCodeBuilder()

const handleInputChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
setSelectedProps(e.currentTarget.name, e.currentTarget.value)
},
[setSelectedProps],
)

const handleSelectChange = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
setSelectedProps(e.currentTarget.name, e.currentTarget.value)
},
[setSelectedProps],
)

const handleToggleChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
setSelectedProps(e.currentTarget.name, e.currentTarget.checked)
},
[setSelectedProps],
)

return (
<div
className={vstack({
alignItems: 'flex-start',
gap: '4',
w: 'full',
})}
>
{Object.keys(props.api).map((key) => (
<div
key={key}
className={vstack({
alignItems: 'flex-start',
w: 'full',
})}
>
<Field>
<Label
className={css({
textTransform: 'capitalize',
})}
htmlFor={key}
size="md"
>
{key}
</Label>
<Show when={props.api[key].type === 'enum'}>
<Select
{...(props.api[key] as EnumResult)}
onChange={handleSelectChange}
options={props.api[key].value as string[]}
value={selectedProps[key] as string}
/>
</Show>
<Show when={props.api[key].type === 'text'}>
<Input
{...(props.api[key] as TextResult)}
id={key}
name={key}
onChange={handleInputChange}
selectedValue={selectedProps[key] as string}
/>
</Show>
<Show when={props.api[key].type === 'boolean'}>
<Toggle
{...(props.api[key] as BooleanResult)}
id={key}
name={key}
onChange={handleToggleChange}
/>
</Show>
</Field>
</div>
))}
</div>
)
}
15 changes: 15 additions & 0 deletions docs/app/components/code-builder/builder-input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use client'

import { Input, type InputProps } from '@cerberus-design/react'
import type { TextResult } from './helpers'

interface BuilderInputProps
extends Omit<InputProps, 'name' | 'type' | 'value'>,
TextResult {
selectedValue: string
}

export default function BuilderInput(props: BuilderInputProps) {
const { selectedValue, ...nativeProps } = props
return <Input {...nativeProps} type="text" value={selectedValue} />
}
87 changes: 87 additions & 0 deletions docs/app/components/code-builder/builder-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Show } from '@cerberus-design/react'
import { css, cx } from '@cerberus/styled-system/css'
import { cq, hstack, vstack } from '@cerberus/styled-system/patterns'
import { type PropsWithChildren } from 'react'
import BuilderSidebar from './builder-sidebar'
import type { BuilderResult } from './helpers'
import BuilderForm from './builder-form'
import BuilderSnippet from './builder-snippet'

interface CodeBuilderProps {
api: Record<string, BuilderResult>
code?: string
}

export default function BuilderLayout(
props: PropsWithChildren<CodeBuilderProps>,
) {
return (
<section
className={cx(
cq({
mb: '6',
}),
vstack(),
)}
>
<div
className={hstack({
cerbGradient: 'purple',
flexDirection: {
'@/sm': 'column',
'@/md': 'row',
},
h: '24rem',
justify: 'space-between',
overflow: 'hidden',
position: 'relative',
pt: {
'@/sm': '4',
'@/md': 'initial',
},
rounded: '2xl',
w: 'full',
})}
>
<div
className={vstack({
justify: 'center',
mx: 'auto',
})}
>
{props.children}
</div>

<BuilderSidebar>
<h2
className={css({
bgColor: 'page.surface.initial',
color: 'page.text.100',
py: '4',
position: 'sticky',
textStyle: 'h6',
top: '0',
})}
>
Preview Playground
</h2>

<BuilderForm api={props.api} />
</BuilderSidebar>
</div>

<Show when={Boolean(props.code)}>
<footer
className={cx(
'expressive-code',
css({
w: 'full',
}),
)}
>
<BuilderSnippet code={props.code!} />
</footer>
</Show>
</section>
)
}
35 changes: 35 additions & 0 deletions docs/app/components/code-builder/builder-select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { type SelectHTMLAttributes } from 'react'
import type { EnumResult } from './helpers'
import { css } from '@cerberus/styled-system/css'
import { focusStates } from '@cerberus-design/panda-preset'

type BuilderSelectProps = Omit<EnumResult, 'value'> &
SelectHTMLAttributes<HTMLSelectElement> & {
options: string[]
}

export default function BuilderSelect(props: BuilderSelectProps) {
const { options, ...nativeProps } = props
return (
<select
{...nativeProps}
className={css({
border: '1px solid',
borderColor: 'action.border.initial',
color: 'page.text.initial',
h: '2.5rem',
pxi: '2',
rounded: 'sm',
...focusStates,
w: 'full',
})}
id={nativeProps.name}
>
{options.map((choice) => (
<option key={choice} value={choice}>
{choice}
</option>
))}
</select>
)
}
41 changes: 41 additions & 0 deletions docs/app/components/code-builder/builder-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { css, cx } from '@cerberus/styled-system/css'
import { scrollable } from '@cerberus/styled-system/patterns'
import type { PropsWithChildren } from 'react'

interface BuilderSidebarProps {}

export default function BuilderSidebar(
props: PropsWithChildren<BuilderSidebarProps>,
) {
return (
<div
className={cx(
scrollable({
direction: 'vertical',
hideScrollbar: true,
}),
css({
bgColor: 'page.surface.initial',
h: {
'@/sm': 'fit-content',
'@/md': 'calc(100% - 0.5rem)',
},
position: 'relative',
pxi: '4',
pb: '4',
marginInlineEnd: {
'@/sm': 'initial',
'@/md': '1',
},
rounded: '2xl',
shadow: 'lg',
w: {
'@/md': '1/3',
},
}),
)}
>
<div>{props.children}</div>
</div>
)
}
48 changes: 48 additions & 0 deletions docs/app/components/code-builder/builder-snippet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use client'

import SyntaxHighlighter from 'react-syntax-highlighter'
import { nightOwl } from 'react-syntax-highlighter/dist/esm/styles/hljs'
import { useCodeBuilder } from '@/app/context/code-builder'
import { useMemo, type PropsWithChildren } from 'react'
import { css } from '@cerberus/styled-system/css'

interface BuilderSnippetProps {
code: string
}

export default function BuilderSnippet(
props: PropsWithChildren<BuilderSnippetProps>,
) {
const { selectedProps } = useCodeBuilder()
const code = useMemo(() => {
return props.code.replace(/{{([^}]+)}}/g, (_, key): string => {
if (key === 'text') {
return (selectedProps[key as keyof typeof selectedProps] ||
'Add Text') as string
}
if (key === 'disabled') {
return `{${selectedProps[key as keyof typeof selectedProps] || 'false'}}`
}
return `"${selectedProps[key as keyof typeof selectedProps] || 'false'}"`
})
}, [props.code, selectedProps])

return (
<SyntaxHighlighter
className={css({
rounded: 'xl',
'& :is(.linenumber)': {
color: '#4b6479',
borderInlineEnd: '1px solid',
borderInlineEndColor: '#272B3B',
marginInlineEnd: '4',
},
})}
language="typescript"
showLineNumbers
style={nightOwl}
>
{code}
</SyntaxHighlighter>
)
}
25 changes: 25 additions & 0 deletions docs/app/components/code-builder/builder-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client'

import { Toggle, useToggle, type ToggleProps } from '@cerberus-design/react'
import type { BooleanResult } from './helpers'

interface BuilderToggleProps
extends Omit<ToggleProps, 'name' | 'type' | 'value'>,
BooleanResult {}

export default function BuilderToggle(props: BuilderToggleProps) {
const { onChange, ...nativeProps } = props
const { checked, handleChange } = useToggle({
checked: nativeProps.value ? nativeProps.name : '',
onChange,
})

return (
<Toggle
{...nativeProps}
checked={checked === nativeProps.name}
onChange={handleChange}
value={String(nativeProps.name)}
/>
)
}
21 changes: 21 additions & 0 deletions docs/app/components/code-builder/code-builder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { type PropsWithChildren } from 'react'
import CodeBuilderProvider from '../../context/code-builder'
import type { BuilderResult } from './helpers'
import BuilderLayout from './builder-layout'

interface CodeBuilderProps {
api: Record<string, BuilderResult>
code?: string
}

export default function CodeBuilder(
props: PropsWithChildren<CodeBuilderProps>,
) {
return (
<CodeBuilderProvider api={props.api}>
<BuilderLayout api={props.api} code={props.code}>
{props.children}
</BuilderLayout>
</CodeBuilderProvider>
)
}
Loading

0 comments on commit 1d7a78e

Please sign in to comment.