Skip to content

Commit

Permalink
docs: Introduce an appearance demo (#4028)
Browse files Browse the repository at this point in the history
* improve that thing

* that thing too

* remove stuff

* extract appearance getter

* add types

* 🤷

* styling yay

* save

* default list box

* !

* style the floating default select

* finally done with styling!

* eeeeh

* remove relative

* remove log

* vertical!

* better

* increase card border color

* props to demo

* styling

* message

* Create many-steaks-shave.md

* fixes
  • Loading branch information
sebald authored Jul 23, 2024
1 parent be5ca6f commit db4fa1d
Show file tree
Hide file tree
Showing 19 changed files with 443 additions and 47 deletions.
8 changes: 8 additions & 0 deletions .changeset/many-steaks-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@marigold/docs": patch
"@marigold/components": patch
"@marigold/theme-b2b": patch
"@marigold/theme-docs": patch
---

docs: Introduce an appearance demo
61 changes: 58 additions & 3 deletions docs/content/__internal__/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,61 @@ caption: A page to test stuff
</Dont>
</Columns>

- foo
- bar
- baz
## Form Controls

<Stack space={8}>
<Select label="Favorite character" placeholder="Select your character">
<Select.Option>Mario</Select.Option>
<Select.Option>Luigi</Select.Option>
<Select.Option>Toad</Select.Option>
<Select.Option>Yoshi</Select.Option>
<Select.Option>Bowser</Select.Option>
<Select.Option>Peach</Select.Option>
</Select>

<Select
label="Favorite character"
placeholder="Select your character"
size="small"
>
<Select.Option>Mario</Select.Option>
<Select.Option>Luigi</Select.Option>
<Select.Option>Toad</Select.Option>
<Select.Option>Yoshi</Select.Option>
<Select.Option>Bowser</Select.Option>
<Select.Option>Peach</Select.Option>
</Select>
</Stack>

### Floating

This is not meant to be used within a regular form. The floating form fields should be used when position over other content (e.g. demos). Be aware that your label will be suffixed with a ":".

<Stack space={8}>
<Select
variant="floating"
label="Favorite character"
placeholder="Select your character"
>
<Select.Option>Mario</Select.Option>
<Select.Option>Luigi</Select.Option>
<Select.Option>Toad</Select.Option>
<Select.Option>Yoshi</Select.Option>
<Select.Option>Bowser</Select.Option>
<Select.Option>Peach</Select.Option>
</Select>

<Select
variant="floating"
size="small"
label="Favorite character"
placeholder="Select your character"
>
<Select.Option>Mario</Select.Option>
<Select.Option>Luigi</Select.Option>
<Select.Option>Toad</Select.Option>
<Select.Option>Yoshi</Select.Option>
<Select.Option>Bowser</Select.Option>
<Select.Option>Peach</Select.Option>
</Select>
</Stack>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ButtonProps } from '@marigold/components';
import { Button } from '@marigold/components';

export default (props: ButtonProps) => <Button {...props}>Press me</Button>;
2 changes: 2 additions & 0 deletions docs/content/components/form/button/button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { Button } from '@marigold/components';

## Appearance

<AppearanceDemo component={title} />

<AppearanceTable component={title} />

## Props
Expand Down
39 changes: 39 additions & 0 deletions docs/lib/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ConfigSchema, Theme } from '@marigold/system';

interface NestedStringObject {
[key: string]: NestedStringObject | string;
}
Expand All @@ -16,3 +18,40 @@ export const iterateTokens = (colors: NestedStringObject, prefix = '') => {
}
return list;
};

const getKeys = (schema: ConfigSchema) => {
return {
variant: schema?.variant && Object.keys(schema?.variant),
size: schema?.size && Object.keys(schema?.size),
};
};

const getKeysFromSlots = (o: {
[slot: string]: { variants: ConfigSchema };
}) => {
let v = new Set<string>();
let s = new Set<string>();

Object.values(o).forEach(value => {
v = new Set([...v, ...Object.keys(value.variants?.variant ?? {})]);
s = new Set([...s, ...Object.keys(value.variants?.size ?? {})]);
});

return { variant: [...v], size: [...s] };
};

/**
* Get variants and sizes (= apperances) from a component
*/
export const getAppearance = (
name: keyof Theme['components'],
theme: Theme
) => {
const styles = theme.components[name] || {};
const appearances =
'variants' in styles
? getKeys(styles.variants as ConfigSchema)
: getKeysFromSlots(styles);

return appearances;
};
112 changes: 111 additions & 1 deletion docs/ui/AppearanceDemo.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,111 @@
export const AppearanceDemo = () => {};
import { getAppearance } from '@/lib/utils';
import { registry } from '@/registry/demos';
import {
Card,
FieldGroup,
MarigoldProvider,
OverlayContainerProvider,
Select,
} from '@/ui';
import type { Theme } from '@/ui';
import type { ComponentType, ReactNode } from 'react';
import { useState } from 'react';

import { useThemeSwitch } from '@/ui/ThemeSwitch';

// Props
// ---------------
export interface AppearanceDemoProps {
component: keyof Theme['components'];
disableLabelWidth?: boolean;
}

// Component
// ---------------
export const AppearanceDemo = ({
component,
disableLabelWidth,
}: AppearanceDemoProps) => {
const name = `${component.toLowerCase()}-appearance` as keyof typeof registry;

if (!registry[name]) {
throw Error(`No demo with name "${name}" found in the registry.`);
}

const Demo: ComponentType<any> = registry[name].demo;
const { current, themes } = useThemeSwitch();
const theme = themes[current];
const appearance = getAppearance(component, theme);

const [selected, setSelected] = useState({
variant: 'default',
size: 'default',
});

const Wrapper = ({ children }: { children: ReactNode }) =>
current === 'core' && !disableLabelWidth ? (
<FieldGroup labelWidth="100px">{children}</FieldGroup>
) : (
children
);

return (
<>
<p>
The appearance of a component can be customized using the{' '}
<code>variant</code> and <code>size</code> props. These props adjust the
visual style and dimensions of the component, available values are based
on the active theme.
</p>
<Card variant="content" p={0}>
<div className="absolute left-4 top-3 flex gap-2">
<Select
label="Variant"
variant="floating"
size="small"
width={36}
selectedKey={selected.variant}
onChange={(val: string) =>
setSelected({ variant: val, size: selected.size })
}
>
<Select.Option id="default">default</Select.Option>
{appearance.variant.map(v => (
<Select.Option key={v} id={v}>
{v}
</Select.Option>
))}
</Select>
<Select
label="Size"
variant="floating"
size="small"
width={32}
selectedKey={selected.size}
onChange={(val: string) =>
setSelected({ variant: selected.variant, size: val })
}
>
<Select.Option id="default">default</Select.Option>
{appearance.size.map(v => (
<Select.Option key={v} id={v}>
{v}
</Select.Option>
))}
</Select>
</div>
<div data-theme={current}>
<OverlayContainerProvider value="portalContainer">
<MarigoldProvider theme={theme}>
<div className="not-prose flex size-full min-h-56 items-center justify-center overflow-x-auto px-4 pb-4 pt-14">
<Wrapper>
<Demo {...selected} />
</Wrapper>
</div>
</MarigoldProvider>
</OverlayContainerProvider>
</div>
</Card>
</>
);
};
30 changes: 3 additions & 27 deletions docs/ui/AppearanceTable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import { Card, ConfigSchema, Inline, Table, Text, Theme } from '@/ui';
import { getAppearance } from '@/lib/utils';
import { Card, Inline, Table, Text, Theme } from '@/ui';

import { useThemeSwitch } from './ThemeSwitch';
import { BlankCanvas } from './icons';
Expand All @@ -9,39 +10,14 @@ export interface AppearanceTableProps {
component: keyof Theme['components'];
}

const getKeys = (schema: ConfigSchema) => {
return {
variant: schema?.variant && Object.keys(schema?.variant),
size: schema?.size && Object.keys(schema?.size),
};
};

const getKeysFromSlots = (o: {
[slot: string]: { variants: ConfigSchema };
}) => {
let v = new Set();
let s = new Set();

Object.values(o).forEach(value => {
v = new Set([...v, ...Object.keys(value.variants?.variant ?? {})]);
s = new Set([...s, ...Object.keys(value.variants?.size ?? {})]);
});

return { variant: [...v], size: [...s] };
};

export const AppearanceTable = ({ component }: AppearanceTableProps) => {
const { current, themes } = useThemeSwitch();

if (!current) {
return null;
}

const styles = themes[current].components[component] || {};
const appearances =
'variants' in styles
? getKeys(styles.variants as ConfigSchema)
: getKeysFromSlots(styles);
const appearances = getAppearance(component, themes[current]);

return (
<Card px={0} py={2}>
Expand Down
8 changes: 3 additions & 5 deletions docs/ui/ComponentDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import {
} from '@/ui';
import type { ReactNode } from 'react';

import { type Theme } from '@marigold/system';

import { useThemeSwitch } from '@/ui/ThemeSwitch';

// Props
Expand Down Expand Up @@ -48,7 +46,7 @@ export const ComponentDemo = ({

const Wrapper = ({ children }: { children: ReactNode }) =>
current === 'core' && !disableLabelWidth ? (
<FieldGroup labelWidth={'100px'}>{children}</FieldGroup>
<FieldGroup labelWidth="100px">{children}</FieldGroup>
) : (
children
);
Expand All @@ -61,13 +59,13 @@ export const ComponentDemo = ({
<Tabs.Item id="code">Code</Tabs.Item>
</Tabs.List>
<Tabs.TabPanel id="preview">
<Card variant="not-inset">
<Card variant="content" p={0}>
<div
data-theme={current}
className="flex size-full min-h-[150px] flex-col [&>*:first-child]:flex [&>*:first-child]:flex-1 [&>*:first-child]:place-items-center [&>*:first-child]:rounded-xl"
>
<OverlayContainerProvider value="portalContainer">
<MarigoldProvider theme={(current && themes[current]) as Theme}>
<MarigoldProvider theme={themes[current]}>
<div className="not-prose size-full overflow-x-auto p-4">
<Wrapper>
<Demo />
Expand Down
22 changes: 15 additions & 7 deletions docs/ui/ThemeSwitch.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use client';

import { type Theme } from '@/ui';
import React, {
import {
ReactNode,
createContext,
useCallback,
useContext,
useEffect,
Expand All @@ -15,19 +16,26 @@ import { useRouter, useSearchParams } from 'next/navigation';
// Context
// ---------------
export interface ThemeSwitchContextType {
current: string | undefined;
current: string;
themes: { [name: string]: Theme };
updateTheme: Function;
}

export const Context = React.createContext({
current: undefined,
themes: {},
} as ThemeSwitchContextType);
export const Context = createContext<ThemeSwitchContextType | null>(null);

// Hook
// ---------------
export const useThemeSwitch = () => useContext(Context);
export const useThemeSwitch = () => {
const ctx = useContext(Context);

if (!ctx) {
throw new Error(
'The "useThemeSwitch" hook can only be used within a <MarigoldThemeSwitch> component!'
);
}

return ctx;
};

// Component
// ---------------
Expand Down
Loading

0 comments on commit db4fa1d

Please sign in to comment.