Skip to content

Commit

Permalink
feat: sidebar layout (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
LIMPIX31 authored May 3, 2024
1 parent 8316d20 commit bbb0ebc
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 11 deletions.
1 change: 1 addition & 0 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
pull_request:
branches: [ dev ]
paths:
- 'app/**'
- 'package.json'
- 'tsconfig.json'
- 'bun.lockb'
Expand Down
5 changes: 5 additions & 0 deletions app/fragments/window/sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { sidebar } from './styles.css.ts'

export function Sidebar() {
return <div className={sidebar}></div>
}
6 changes: 6 additions & 0 deletions app/fragments/window/sidebar/styles.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { style } from '@vanilla-extract/css'

export const sidebar = style({
width: '4rem',
position: 'relative',
})
17 changes: 13 additions & 4 deletions app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import '&theme/preflight.css.ts'
import '&theme/provider.tsx'
import '&theme/preflight.css.ts'
import '&theme/provider.tsx'

import { Button } from '&ui/button'
import { Sidebar } from '&fragments/window/sidebar'
import { Box } from '&ui/layout'
import { Row } from '&ui/layout'

export function Root() {
return <Button style={{ margin: '50px' }}>Launch</Button>
return (
<Row>
<Sidebar />
<Box bg='background' roundedLeft='m'>
{/* TODO */}
</Box>
</Row>
)
}
31 changes: 31 additions & 0 deletions app/shared/nanolib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const { entries } = Object

export type Leaves<T> = T extends object
? { [K in keyof T]: `${Exclude<K, symbol>}${Leaves<T[K]> extends never ? '' : `.${Leaves<T[K]>}`}` }[keyof T]
: never

type PathAccess<T, P extends string> = P extends `${infer K}.${infer R}`
? K extends keyof T
? PathAccess<T[K], R>
: never
: P extends keyof T
? T[P]
: never

export function leaves<T extends object>(target: T, prefix: string[] = []): Leaves<T>[] {
const list = []

for (const [key, value] of entries(target)) {
if (typeof value === 'object') {
list.push(...leaves(value, [...prefix, key]))
} else {
list.push([...prefix, key].join('.'))
}
}

return list as Leaves<T>[]
}

export function pathAccess<T extends object, P extends Leaves<T>>(target: T, path: P) {
return path.split('.').reduce((a, c) => Reflect.get(a as object, c), target) as PathAccess<T, P>
}
7 changes: 3 additions & 4 deletions app/theme/base.css.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { clashDisplay } from '&theme/fonts.css.ts'
import { manrope } from '&theme/fonts.css.ts'
import { geistMono } from '&theme/fonts.css.ts'

import { clashDisplay } from './fonts.css.ts'
import { manrope } from './fonts.css.ts'
import { geistMono } from './fonts.css.ts'
import type { ThemePart } from './shared.ts'
import type { vars } from './vars.css.ts'

Expand Down
1 change: 1 addition & 0 deletions app/theme/dark.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const theme = createTheme(vars, {
readable: '#18181b',
},
gray: {
surface: '#212124',
input: '#3b3a38',
},
},
Expand Down
1 change: 1 addition & 0 deletions app/theme/light.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const theme = createTheme(vars, {
readable: '#f9f1e9',
},
gray: {
surface: '#ece3d9',
input: '#d2cfc9',
},
},
Expand Down
9 changes: 7 additions & 2 deletions app/theme/preflight.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ globalStyle('*', {
globalStyle('body', {
'@layer': {
[preflight]: {
minHeight: '100vh',
backgroundColor: vars.color.background,
height: '100vh',
backgroundColor: vars.color.gray.surface,
fontFamily: vars.font.sans,
fontSize: '87.5%',
transition: `all ${vars.transition.duration.l} ${vars.transition.timing}`,
Expand Down Expand Up @@ -55,3 +55,8 @@ globalStyle('img', {
},
},
})

globalStyle('#root', {
height: '100vh',
display: 'flex',
})
18 changes: 17 additions & 1 deletion app/theme/vars.css.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { createThemeContract } from '@vanilla-extract/css'
import type { style } from '@vanilla-extract/css'
import { createThemeContract } from '@vanilla-extract/css'

import { leaves } from '&shared/nanolib.ts'
import { pathAccess } from '&shared/nanolib.ts'

const typography = {
size: null,
Expand All @@ -20,6 +24,7 @@ export const vars = createThemeContract({
readable: null,
},
gray: {
surface: null,
input: null,
},
},
Expand Down Expand Up @@ -73,3 +78,14 @@ export const vars = createThemeContract({
},
},
})

export function mapVars<T extends object>(vars: T, fn: (val: keyof T) => Parameters<typeof style>[0]) {
return Object.fromEntries(Object.entries(vars).map(([key, value]) => [key, fn(value)])) as Record<
keyof T,
Parameters<typeof style>[0]
>
}

export function mapVarsPath<T extends object>(vars: T, fn: (val: string) => Parameters<typeof style>[0]) {
return Object.fromEntries(leaves(vars).map((path) => [path, fn(pathAccess(vars, path) as string)]))
}
26 changes: 26 additions & 0 deletions app/ui/layout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { clsx } from 'clsx'

import type { LayoutProps } from './shared.ts'
import { useStyle } from './shared.ts'
import { box } from './styles.css.ts'
import { col } from './styles.css.ts'
import { row } from './styles.css.ts'

export function Row(props: LayoutProps) {
const { style, rest } = useStyle(props)
return <div {...rest} className={clsx(row, style)} />
}

export function Col(props: LayoutProps) {
const { style, rest } = useStyle(props)
return <div {...rest} className={clsx(col, style)} />
}

export type BoxProps = Omit<LayoutProps, 'gap' | 'grow'>

export function Box(props: BoxProps) {
const { style, rest } = useStyle(props)
return <div {...rest} className={clsx(box, style)} />
}

export type { LayoutProps }
32 changes: 32 additions & 0 deletions app/ui/layout/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { ComponentProps } from 'react'

import { clsx } from 'clsx'

import type { Leaves } from '&shared/nanolib.ts'
import type { vars } from '&theme/vars.css.ts'
import { variants } from '&ui/layout/styles.css.ts'

export type LayoutProps = ComponentProps<'div'> & {
gap?: keyof typeof vars.space
p?: keyof typeof vars.space
bg?: Leaves<typeof vars.color>
rounded?: keyof typeof vars.rounded
roundedLeft?: keyof typeof vars.rounded
grow?: boolean
}

export function useStyle(props: LayoutProps) {
const { gap, p, bg, grow, rounded, roundedLeft, ...rest } = props

return {
style: clsx(
gap && variants.gap[gap],
p && variants.p[p],
bg && variants.bg[bg],
grow && variants.grow.true,
rounded && variants.rounded[rounded],
roundedLeft && variants.roundedLeft[roundedLeft],
),
rest,
}
}
54 changes: 54 additions & 0 deletions app/ui/layout/styles.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { style } from '@vanilla-extract/css'
import { styleVariants } from '@vanilla-extract/css'

import { mapVars } from '&theme/vars.css.ts'
import { mapVarsPath } from '&theme/vars.css.ts'
import { vars } from '&theme/vars.css.ts'

const base = style({
display: 'flex',
transitionProperty: 'all',
transitionDuration: vars.transition.duration.m,
transitionTimingFunction: vars.transition.timing,
})

export const variants = {
gap: styleVariants(mapVars(vars.space, (gap) => ({ gap }))),
p: styleVariants(mapVars(vars.space, (padding) => ({ padding }))),
bg: styleVariants(mapVarsPath(vars.color, (backgroundColor) => ({ backgroundColor }))),
rounded: styleVariants(mapVars(vars.rounded, (borderRadius) => ({ borderRadius }))),
roundedLeft: styleVariants(
mapVars(vars.rounded, (radius) => ({
borderTopLeftRadius: radius,
borderBottomLeftRadius: radius,
})),
),
grow: styleVariants({
true: {
flexGrow: 1,
},
}),
}

export const row = style([
base,
{
width: '100%',
flexDirection: 'row',
},
])

export const col = style([
base,
{
height: '100%',
flexDirection: 'column',
},
])

export const box = style([
base,
{
flexGrow: 1,
},
])

0 comments on commit bbb0ebc

Please sign in to comment.