Skip to content

Commit 7acc63f

Browse files
committed
Bring styles closer to new designs
1 parent f7a7adc commit 7acc63f

File tree

2 files changed

+108
-66
lines changed

2 files changed

+108
-66
lines changed

src/app/(main)/resources/[category]/category-tools-libraries-section.tsx

Lines changed: 107 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import path from "node:path"
22
import { glob } from "node:fs/promises"
33
import { readFile } from "node:fs/promises"
44
import matter from "gray-matter"
5-
65
import type { CSSProperties } from "react"
6+
77
import { Button } from "@/app/conf/_design-system/button"
88
import blurCorner from "./blur-corner.webp"
99
import { Eyebrow } from "@/_design-system/eyebrow"
1010
import slugMap from "@/code/slug-map.json"
1111
import { type Topic } from "@/resources/types"
1212
import { StripesDecoration } from "@/app/conf/_design-system/stripes-decoration"
1313

14-
import { ChevronRight } from "@/app/conf/_design-system/pixelarticons/chevron-right"
1514
import { IconSpritesheet, IconName } from "./spritesheet"
15+
import CaretDown from "@/app/conf/_design-system/pixelarticons/caret-down.svg?svgr"
1616

1717
interface LibraryEntry {
1818
name: string
@@ -72,7 +72,7 @@ export async function CategoryToolsLibrariesSection({
7272
const libraries = await librariesPromise
7373
const filtered = libraries.filter(item => item.tags.includes(category))
7474

75-
const grouped = Array.from(
75+
const sortedGroups = Array.from(
7676
filtered.reduce<Map<string, LibraryEntry[]>>((acc, item) => {
7777
const list = acc.get(item.group) ?? []
7878
list.push(item)
@@ -91,6 +91,14 @@ export async function CategoryToolsLibrariesSection({
9191
}))
9292
.sort((a, b) => b.items.length - a.items.length)
9393

94+
const grouped: GroupData[] = sortedGroups.map((group, index) => {
95+
const nextLength = sortedGroups[index + 1]?.items.length ?? 0
96+
const columns =
97+
nextLength > 0 && group.items.length >= nextLength * 1.9 ? 2 : 1
98+
const breakIndex = columns === 2 ? Math.ceil(group.items.length / 2) : 0
99+
return { ...group, columns, breakIndex }
100+
})
101+
94102
if (grouped.length === 0) {
95103
return null
96104
}
@@ -124,73 +132,108 @@ export async function CategoryToolsLibrariesSection({
124132
</Button>
125133
</div>
126134

127-
<div className="flex flex-wrap gap-4 pb-2 lg:overflow-visible">
128-
{grouped.map((group, index) => {
129-
const nextLength = grouped[index + 1]?.items.length ?? 0
130-
const columns =
131-
nextLength > 0 && group.items.length >= nextLength * 1.9 ? 2 : 1
132-
const listStyle = { "--item-columns": columns } as CSSProperties
133-
const breakIndex =
134-
columns === 2 ? Math.floor(group.items.length / 2) : 0
135-
136-
return (
137-
<div
138-
key={group.id}
139-
className="min-w-[480px] shrink-0 grow border border-neu-200 bg-neu-50 dark:border-neu-100 dark:bg-neu-50/25 lg:w-1/3 lg:min-w-0"
140-
>
141-
<div className="typography-body-lg flex items-center gap-3 border-b border-inherit bg-neu-50 text-neu-900 dark:bg-transparent">
142-
<div className="border-r border-inherit p-3">
143-
<IconSpritesheet
144-
sprite={group.id as IconName}
145-
className="size-10 text-neu-800 dark:text-neu-700"
146-
/>
147-
</div>
148-
<div className="px-4 py-3">{group.name}</div>
149-
<div className="border-l border-inherit p-3 md:hidden">
150-
{/* TODO: On mobile */}
151-
<ChevronRight className="rotate-90" />
152-
</div>
153-
</div>
154-
<ul
155-
className="gap-0 divide-y divide-neu-200 dark:divide-neu-100 lg:[column-count:var(--item-columns,1)]"
156-
style={listStyle}
157-
>
158-
{group.items.map((item, i) => (
159-
<li
160-
key={`${group.id}-${item.name}`}
161-
style={
162-
breakIndex
163-
? {
164-
borderTop: i === breakIndex ? "none" : "",
165-
borderLeftWidth: i >= breakIndex ? "1px" : "",
166-
}
167-
: {}
168-
}
169-
>
170-
{item.href ? (
171-
<a
172-
href={item.href}
173-
className="flex items-center justify-between bg-neu-0/40 px-4 py-3 text-neu-900 transition-colors hover:bg-neu-0 hover:duration-0"
174-
>
175-
{item.name}
176-
</a>
177-
) : (
178-
<span className="flex items-center justify-between bg-neu-0/40 px-4 py-3 text-neu-900">
179-
{item.name}
180-
</span>
181-
)}
182-
</li>
183-
))}
184-
</ul>
185-
</div>
186-
)
187-
})}
135+
<div className="flex flex-wrap gap-4 pb-2 max-md:flex-col md:flex-nowrap md:items-start">
136+
{distributeToColumns(grouped).map((column, colIndex) => (
137+
<div
138+
key={colIndex}
139+
className="flex w-full flex-col gap-4 max-md:contents"
140+
>
141+
{column.map(group => (
142+
<Group key={group.id} group={group} />
143+
))}
144+
</div>
145+
))}
188146
</div>
189147
</section>
190148
</div>
191149
)
192150
}
193151

152+
interface GroupData {
153+
id: string
154+
name: string
155+
items: LibraryEntry[]
156+
columns: 1 | 2
157+
breakIndex: number
158+
}
159+
160+
function distributeToColumns(groups: GroupData[]): [GroupData[], GroupData[]] {
161+
const left: GroupData[] = []
162+
const right: GroupData[] = []
163+
164+
let leftHeight = 0
165+
let rightHeight = 0
166+
167+
for (const group of groups) {
168+
const itemRows =
169+
group.columns === 2
170+
? Math.ceil(group.items.length / 2)
171+
: group.items.length
172+
const height = itemRows + 1
173+
if (leftHeight <= rightHeight) {
174+
left.push(group)
175+
leftHeight += height
176+
} else {
177+
right.push(group)
178+
rightHeight += height
179+
}
180+
}
181+
182+
return [left, right]
183+
}
184+
185+
function Group({ group }: { group: GroupData }) {
186+
const listStyle = { "--item-columns": group.columns } as CSSProperties
187+
188+
return (
189+
<div className="shrink-0 grow border border-neu-200 bg-neu-50 dark:border-neu-100 dark:bg-neu-50/25 lg:min-w-0 xl:min-w-[480px]">
190+
<div className="typography-body-lg flex items-center border-b border-inherit bg-neu-50 text-neu-900 dark:bg-transparent">
191+
<div className="border-r border-inherit p-2 lg:p-3">
192+
<IconSpritesheet
193+
sprite={group.id as IconName}
194+
className="size-8 text-neu-800 dark:text-neu-700 lg:size-10"
195+
/>
196+
</div>
197+
<div className="p-2 lg:px-4 lg:py-3">{group.name}</div>
198+
<div className="ml-auto flex aspect-square h-12 shrink-0 items-center justify-center border-l border-inherit p-2 md:hidden">
199+
<CaretDown className="size-6 shrink-0 fill-neu-700" />
200+
</div>
201+
</div>
202+
<ul
203+
className="divide-y divide-neu-200 dark:divide-neu-100 lg:[column-count:var(--item-columns,1)]"
204+
style={listStyle}
205+
>
206+
{group.items.map((item, i) => (
207+
<li
208+
key={`${group.id}-${item.name}`}
209+
style={
210+
group.breakIndex
211+
? {
212+
borderTop: i === group.breakIndex ? "none" : "",
213+
borderLeftWidth: i >= group.breakIndex ? "1px" : "",
214+
}
215+
: {}
216+
}
217+
>
218+
{item.href ? (
219+
<a
220+
href={item.href}
221+
className="flex items-center justify-between bg-neu-0/40 px-4 py-3 text-neu-900 transition-colors hover:bg-neu-0 hover:duration-0"
222+
>
223+
{item.name}
224+
</a>
225+
) : (
226+
<span className="flex items-center justify-between bg-neu-0/40 px-4 py-3 text-neu-900">
227+
{item.name}
228+
</span>
229+
)}
230+
</li>
231+
))}
232+
</ul>
233+
</div>
234+
)
235+
}
236+
194237
function Stripes() {
195238
return (
196239
<div

src/app/conf/_design-system/pixelarticons/caret-down.svg

Lines changed: 1 addition & 2 deletions
Loading

0 commit comments

Comments
 (0)