-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
179 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export const colors = { | ||
primary: '96 100% 68%', | ||
accent: '96 100% 88%', | ||
background: '0 0% 100%', | ||
foreground: '0 0% 7%', | ||
success: '116 78% 65%', | ||
error: '0 100% 60%', | ||
warning: '40 100% 60%', | ||
info: '220 70% 45%', | ||
contrast: { | ||
100: '0 0% 93%', | ||
200: '0 0% 82%', | ||
300: '0 0% 70%', | ||
400: '0 0% 54%', | ||
500: '0 0% 34%', | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
'use client'; | ||
|
||
import { createContext, type PropsWithChildren, useContext } from 'react'; | ||
|
||
type Colors = { | ||
primary?: string; | ||
accent?: string; | ||
success?: string; | ||
error?: string; | ||
warning?: string; | ||
info?: string; | ||
background?: string; | ||
foreground?: string; | ||
contrast?: { | ||
100?: string; | ||
200?: string; | ||
300?: string; | ||
400?: string; | ||
500?: string; | ||
}; | ||
}; | ||
|
||
type Props = { | ||
colors: Colors; | ||
}; | ||
|
||
const colorToHslValue = (color: string) => | ||
color.startsWith('rgb') ? `from ${color} h s l` : color; | ||
|
||
const colorToCssVar = (name: string, color: string) => `--${name}: ${colorToHslValue(color)};`; | ||
|
||
function colorsToCssVars(colors: Colors) { | ||
const { contrast, ...rest } = colors; | ||
|
||
const mainColors = Object.entries(rest).map(([key, color]) => | ||
color != null ? colorToCssVar(key, color) : null, | ||
); | ||
|
||
const contrastColors = Object.entries(contrast ?? {}).map(([value, color]) => | ||
color != null ? colorToCssVar(`contrast-${value}`, color) : null, | ||
); | ||
|
||
return [...mainColors, ...contrastColors].filter(Boolean).join('\n'); | ||
} | ||
|
||
export const CssTheme = ({ colors }: Props) => { | ||
return ( | ||
<style data-makeswift="theme">{`:root { | ||
${colorsToCssVars(colors)} | ||
} | ||
`}</style> | ||
); | ||
}; | ||
|
||
const PropsContext = createContext<Props>({ colors: {} }); | ||
|
||
export const PropsContextProvider = ({ value, children }: PropsWithChildren<{ value: Props }>) => ( | ||
<PropsContext.Provider value={value}>{children}</PropsContext.Provider> | ||
); | ||
|
||
type ColorMap<K extends string> = { | ||
[key in K]?: string | ColorMap<K>; | ||
}; | ||
|
||
function mergeColors<K extends string>(left: ColorMap<K>, right: ColorMap<K>): ColorMap<K> { | ||
const result = { ...left }; | ||
for (const key in right) { | ||
const rightValue = right[key]; | ||
if (rightValue != null) { | ||
result[key] = | ||
typeof rightValue === 'object' ? mergeColors(left[key] ?? {}, rightValue) : rightValue; | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
export const MakeswiftCssTheme = ({ colors }: Props) => { | ||
const { colors: passedColors } = useContext(PropsContext); | ||
return <CssTheme colors={mergeColors(passedColors, colors)} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { MakeswiftComponent } from '@makeswift/runtime/next'; | ||
import { type ComponentPropsWithoutRef } from 'react'; | ||
|
||
import { getComponentSnapshot } from '~/lib/makeswift/client'; | ||
|
||
import { CssTheme as CssThemeClient, PropsContextProvider } from './client'; | ||
import { COMPONENT_TYPE } from './register'; | ||
|
||
type Props = ComponentPropsWithoutRef<typeof CssThemeClient> & { | ||
snapshotId?: string; | ||
label?: string; | ||
}; | ||
|
||
export const CssTheme = async ({ | ||
snapshotId = 'site-theme', | ||
label = 'Site Theme', | ||
...props | ||
}: Props) => { | ||
const snapshot = await getComponentSnapshot(snapshotId); | ||
|
||
return ( | ||
<PropsContextProvider value={props}> | ||
<MakeswiftComponent label={label} snapshot={snapshot} type={COMPONENT_TYPE} /> | ||
</PropsContextProvider> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Color, Shape } from '@makeswift/runtime/controls'; | ||
|
||
import { runtime } from '~/lib/makeswift/runtime'; | ||
import { colors } from 'app/theme'; | ||
|
||
import { MakeswiftCssTheme } from './client'; | ||
|
||
export const COMPONENT_TYPE = 'catalyst-makeswift-theme-provider'; | ||
|
||
const toHsl = (hslValues: string) => `hsl(${hslValues})`; | ||
|
||
runtime.registerComponent(MakeswiftCssTheme, { | ||
type: COMPONENT_TYPE, | ||
label: 'MakeswiftCssTheme (private)', | ||
hidden: true, | ||
props: { | ||
colors: Shape({ | ||
type: { | ||
primary: Color({ label: 'Primary', defaultValue: toHsl(colors.primary) }), | ||
accent: Color({ label: 'Accent', defaultValue: toHsl(colors.accent) }), | ||
success: Color({ label: 'Success', defaultValue: toHsl(colors.success) }), | ||
error: Color({ label: 'Error', defaultValue: toHsl(colors.error) }), | ||
warning: Color({ label: 'Warning', defaultValue: toHsl(colors.warning) }), | ||
info: Color({ label: 'Info', defaultValue: toHsl(colors.info) }), | ||
background: Color({ label: 'Background', defaultValue: toHsl(colors.background) }), | ||
foreground: Color({ label: 'Foreground', defaultValue: toHsl(colors.foreground) }), | ||
contrast: Shape({ | ||
type: { | ||
100: Color({ label: 'Contrast 100', defaultValue: toHsl(colors.contrast[100]) }), | ||
200: Color({ label: 'Contrast 200', defaultValue: toHsl(colors.contrast[200]) }), | ||
300: Color({ label: 'Contrast 300', defaultValue: toHsl(colors.contrast[300]) }), | ||
400: Color({ label: 'Contrast 400', defaultValue: toHsl(colors.contrast[400]) }), | ||
500: Color({ label: 'Contrast 500', defaultValue: toHsl(colors.contrast[500]) }), | ||
}, | ||
}), | ||
}, | ||
}), | ||
}, | ||
}); |