Skip to content

Instantly share code, notes, and snippets.

@panoply
Created June 23, 2025 03:22
Show Gist options
  • Save panoply/ab057458b96ade18edab26a95ee6e783 to your computer and use it in GitHub Desktop.
Save panoply/ab057458b96ade18edab26a95ee6e783 to your computer and use it in GitHub Desktop.
import s from 'sin'
import Badge from '../badge'
import Icon from '../icon'
const Sidebar = s((attrs, content, state) => s`aside.sidebar
pt 24
w 25%
min-width 240!
max-width 320
min-height 0
flex-shrink 0
bg linear-gradient(-135deg, rgb(255 255 255/.15), transparent), linear-gradient(oklch(95% 0.02 261.3/.25), oklch(85% 0.03 261.3/.25))
bs inset 0 .5 .5 .5 white, inset 10 0 48 24 rgb(255 255 255/.35), inset -4 0 40 -4 rgb(0 0 0/.05)
`(attrs,
s`
overflow scroll
h 100%
`(
content
)
)
)
export default Sidebar
Sidebar.section = s(({ open = true }) => ({
title,
expand = true,
onsearch,
onmore,
onadd
}, xs) =>
s`section
p 16 0
bs 0 14 4 -16 rgb(0 0 0/.35)
:first-child {
pt 0
}
:last-child {
bs none
}
`(
s`header
d flex
ai center
p 0 16
fg 1
gap 6
strong {
fs 14
mr auto
}
button {
br 6
transition background-color $d, box-shadow $d
> icon {
w 24
h 24
p 4
d block
}
:first-of-type > icon {
transition rotate $d
rotate ${ open ? 180 : 90 }
}
:hover {
bc white
bs 0 0 10 -2 rgb(0 0 0/.1)
}
}
`(
expand && s`button`({ onclick: () => open = !open }, Icon.chevron),
s`strong`(title),
onsearch && s`button`({ onclick: onsearch }, Icon.search ),
onmore && s`button`({ onclick: onmore }, Icon.more),
onadd && s`button`({ onclick: onadd }, Icon.plus )
),
open && s`nav
gap 4
overflow hidden
max-height ${ x => x.scrollHeight }
transition max-height $d
:hover > a[active]::after {
transform scaleX(0)
}
[animate] {
max-height 0
}
`({
dom: s.animate
},
xs
)
)
)
Sidebar.item = s(({
open = false
}) => ({
title,
expanded = false,
icon,
...attrs
}, content, { route }) =>
s``(
s`a
position relative
d flex
p 8 12
m 0 8
ai center
jc space-between
br 12
transition background $d, color $d
::after {
content ""
position absolute
l -8
t 10%
w 3
h 80%
br 0 3 3 0
bc rgb(0 0 0/.25)
transition transform $d
transform-origin 0% 50%
transform scaleX(0)
}
[active] {
c oklch(from $blue calc(l * .8) calc(c * .8) h)
fw bold
:hover {
c oklch(from $blue calc(l * .8) calc(c * .8) h)
bc $blue/.15
}
::after {
bc oklch(from $blue calc(l * .8) calc(c * .8) h)
transform scaleX(1)
}
}
:hover {
c black
bc rgb(0 0 0/.05)
::after {
transform scaleX(1)!
}
}
`({
active : attrs.href && route.has(attrs.href),
onclick : () => open = route.has(attrs.href),
...attrs
},
s`span
position relative
d flex
ai center
gap 8
min-width 0
`(
icon && icon` w 20;flex-shrink 0`,
s`.ellipsis ; min-width 0`(title),
attrs.badge && Badge` r -20;t -8`(1)
),
expanded && s`button
d flex
br 4
transition background-color $d, box-shadow $d
> icon {
w 20
h 20
p 2
d block
flex-shrink 0
transition transform $d
transform rotate(${ (open || route.has(attrs.href)) ? 180 : 90 })
}
:not([active] &):hover {
bc white
bs 0 0 10 -2 rgb(0 0 0/.1)
}
`({
onclick: (e) => {
e.preventDefault()
e.stopPropagation()
open = !open
}
},
Icon.chevron`.chevron`
)
)
,
expanded && (open || route.has(attrs.href)) && s`
pl 16
transition max-height $d
overflow hidden
max-height ${ x => x.scrollHeight }
[animate] {
max-height 0
}
`({
dom: s.animate
},
content
)
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment