Skip to content

Commit f34d1b3

Browse files
authored
Merge pull request #21 from alexanderop/toc-fix
Implement 5x5 grid layout system
2 parents 64a88f1 + 07d0be6 commit f34d1b3

17 files changed

Lines changed: 137 additions & 124 deletions

assets/css/prose-mobile.css

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* Mobile-specific prose styles for better code block handling */
2+
@media (max-width: 640px) {
3+
/* Keep code blocks within container bounds */
4+
.prose pre,
5+
.prose .prose-pre {
6+
border-radius: 0.5rem;
7+
max-width: 100%;
8+
}
9+
10+
.prose .prose-pre-body {
11+
overflow-x: auto;
12+
-webkit-overflow-scrolling: touch;
13+
}
14+
15+
/* Ensure code blocks are scrollable */
16+
.prose pre code,
17+
.prose .prose-pre-body code {
18+
display: block;
19+
overflow-x: auto;
20+
white-space: pre;
21+
word-wrap: normal;
22+
word-break: normal;
23+
}
24+
25+
/* Visual indicator for scrollable area */
26+
.prose .prose-pre-body::-webkit-scrollbar {
27+
height: 8px;
28+
}
29+
30+
.prose .prose-pre-body::-webkit-scrollbar-track {
31+
background: rgba(0, 0, 0, 0.1);
32+
}
33+
34+
.prose .prose-pre-body::-webkit-scrollbar-thumb {
35+
background: rgba(0, 0, 0, 0.3);
36+
border-radius: 4px;
37+
}
38+
}

components/Breadcrumbs.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,33 @@ useBreadcrumbStructuredData(items)
1414
<template>
1515
<nav
1616
aria-label="Breadcrumb navigation"
17-
class="breadcrumbs"
17+
class="breadcrumbs max-w-full overflow-x-auto"
1818
>
1919
<ul class="text-sm flex flex-wrap gap-2 items-center">
2020
<li
2121
v-for="(item, index) in items"
2222
:key="index"
23-
class="flex gap-2 items-center"
23+
class="flex gap-2 min-w-0 items-center"
2424
>
2525
<template v-if="item.url">
2626
<NuxtLink
2727
:to="item.url"
28-
class="text-[var(--color-text-muted)] transition-colors hover:text-[var(--color-primary)]"
28+
class="text-[var(--color-text-muted)] max-w-[200px] min-w-0 break-words transition-colors hover:text-[var(--color-primary)] sm:max-w-none"
2929
>
3030
{{ item.name }}
3131
</NuxtLink>
3232
</template>
3333

3434
<template v-else>
35-
<span class="text-[var(--color-text)]">
35+
<span class="text-[var(--color-text)] max-w-[200px] min-w-0 break-words sm:max-w-none">
3636
{{ item.name }}
3737
</span>
3838
</template>
3939

4040
<Icon
4141
v-if="index < items.length - 1"
4242
name="i-lucide-chevron-right"
43-
class="text-[var(--color-text-muted)] h-4 w-4"
43+
class="text-[var(--color-text-muted)] flex-shrink-0 h-4 w-4"
4444
/>
4545
</li>
4646
</ul>

components/TableOfContents.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ provide(tocKey, {
3333
<template>
3434
<nav
3535
v-if="hasEnoughHeadings"
36-
class="w-full hidden lg:block"
36+
class="w-full"
3737
aria-label="Table of contents"
3838
>
3939
<div class="p-6 rounded-lg bg-[var(--color-bg-secondary)]">

components/TheFooter.vue

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,18 @@ const currentYear = new Date().getFullYear()
1111

1212
<template>
1313
<footer
14-
class="w-full"
14+
class="flex w-full items-center"
1515
:class="[{ 'mt-auto': !noMarginTop }]"
1616
>
17-
<div class="container-app">
18-
<div class="py-6 flex flex-col items-center justify-between sm:py-4 sm:flex-row-reverse">
19-
<BaseSocials centered />
17+
<div class="py-6 flex flex-col w-full items-center justify-between sm:py-4 sm:flex-row-reverse">
18+
<BaseSocials centered />
2019

21-
<div class="my-2 flex flex-col whitespace-nowrap items-center sm:flex-row">
22-
<span>Copyright © {{ currentYear }}</span>
20+
<div class="my-2 flex flex-col whitespace-nowrap items-center sm:flex-row">
21+
<span>Copyright © {{ currentYear }}</span>
2322

24-
<span class="hidden sm:inline">&nbsp;|&nbsp;</span>
23+
<span class="hidden sm:inline">&nbsp;|&nbsp;</span>
2524

26-
<span>All rights reserved.</span>
27-
</div>
25+
<span>All rights reserved.</span>
2826
</div>
2927
</div>
3028
</footer>

components/TheHeader.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,18 @@ watch(
3535
<div class="bg-[var(--color-header-bg)] w-full">
3636
<div
3737
id="nav-container"
38-
class="container-app py-4 flex flex-col items-center justify-between relative sm:py-6 sm:flex-row"
38+
class="px-4 py-4 flex w-full items-center justify-between relative sm:px-6 sm:py-6"
3939
>
4040
<NuxtLink
4141
to="/"
42-
class="text-xl leading-8 font-semibold py-1 whitespace-nowrap absolute sm:text-2xl sm:leading-none sm:static"
42+
class="text-xl leading-8 font-semibold py-1 whitespace-nowrap sm:text-2xl sm:leading-none"
4343
>
4444
{{ appConfig.site.title }}
4545
</NuxtLink>
4646

4747
<nav
4848
id="nav-menu"
49-
class="flex flex-col w-full items-center sm:ms-2 sm:py-0 sm:flex-row sm:justify-end sm:space-x-4"
49+
class="flex items-center sm:ms-2"
5050
>
5151
<BaseMobileMenuToggle
5252
id="menu-btn"
@@ -57,12 +57,12 @@ watch(
5757

5858
<ul
5959
id="menu-items"
60-
class="sm:mt-0 sm:flex sm:gap-x-5 sm:w-auto sm:items-center"
60+
class="sm:mt-0 sm:flex sm:gap-x-5 sm:items-center"
6161
:class="[
6262
menuItemStyles,
6363
// Mobile styles: toggle between 'grid' and 'hidden'
6464
menuOpen
65-
? 'grid mt-4 w-44 grid-cols-2 place-content-center gap-2'
65+
? 'grid mt-4 w-44 grid-cols-2 place-content-center gap-2 absolute top-full left-1/2 -translate-x-1/2 bg-[var(--color-header-bg)] rounded-lg shadow-lg z-50'
6666
: 'hidden',
6767
]"
6868
>

composables/useStaggeredAnimation.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,33 @@ interface StaggeredAnimationOptions {
1010
}
1111

1212
export function useStaggeredAnimation(options: StaggeredAnimationOptions = {}) {
13-
// Configuration with defaults
13+
if (!isClientEnvironment) {
14+
return {
15+
animatedCount: readonly(ref(0)),
16+
error: readonly(ref<Error | null>(null)),
17+
isAnimating: readonly(ref(false)),
18+
isComplete: computed(() => false),
19+
replay: () => {},
20+
resetAnimations: () => {},
21+
}
22+
}
23+
1424
const {
1525
selector = '.animate',
1626
staggerDelay = 100,
1727
initialDelay = 100,
1828
animationClass = 'show',
1929
} = options
2030

21-
// Primary State
2231
const isAnimating = ref(false)
2332
const animatedCount = ref(0)
2433

25-
// State Metadata
2634
const error = ref<Error | null>(null)
2735

28-
// Computed Properties
2936
const isComplete = computed(() =>
3037
animatedCount.value > 0 && !isAnimating.value,
3138
)
3239

33-
// Methods
3440
const animateElements = () => {
3541
try {
3642
error.value = null
@@ -80,30 +86,22 @@ export function useStaggeredAnimation(options: StaggeredAnimationOptions = {}) {
8086
setTimeout(animateElements, initialDelay)
8187
}
8288

83-
// Lifecycle Hooks
8489
onMounted(() => {
8590
setTimeout(animateElements, initialDelay)
8691
})
8792

88-
// Watchers
8993
const route = useRoute()
9094
watchEffect(() => {
9195
if (route.path) {
9296
replay()
9397
}
9498
})
9599

96-
// Return public API
97100
return {
98-
99101
animatedCount: readonly(animatedCount),
100-
101102
error: readonly(error),
102-
// State
103103
isAnimating: readonly(isAnimating),
104-
// Computed
105104
isComplete,
106-
// Methods
107105
replay,
108106
resetAnimations,
109107
}

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ export default antfu(
409409
},
410410
],
411411
'ts/no-floating-promises': 'error',
412+
'ts/prefer-optional-chain': 'error',
412413
},
413414
},
414415
{

layouts/blog.vue

Lines changed: 0 additions & 60 deletions
This file was deleted.

layouts/default.vue

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,38 @@
11
<script setup lang="ts">
2-
// Default layout with header and footer
2+
// Default layout with 5x5 grid structure
33
</script>
44

55
<template>
6-
<div class="font-mono flex flex-col min-h-screen">
7-
<TheHeader />
6+
<div class="font-mono grid grid-rows-[auto_1fr_1fr_1fr_auto] grid-cols-1 min-h-screen sm:grid-cols-5">
7+
<!-- Header - spans full width on mobile, columns 2-4 on desktop -->
8+
<TheHeader class="col-span-1 row-start-1 row-end-2 sm:col-start-2 sm:col-end-5" />
89

10+
<!-- Left Sidebar - hidden on mobile, spans row 2-4 in column 1 on desktop -->
11+
<aside
12+
id="left-sidebar"
13+
class="hidden sm:col-start-1 sm:row-start-2 sm:col-end-2 sm:row-end-5 sm:block"
14+
>
15+
<div
16+
id="left-sidebar-content"
17+
class="px-4 top-4 sticky"
18+
/>
19+
</aside>
20+
21+
<!-- Main Content - full width on mobile, spans columns 2-4 on desktop -->
922
<main
1023
id="main-content"
11-
class="flex-1"
24+
class="px-4 col-span-1 row-start-2 row-end-5 sm:px-0 sm:col-start-2 sm:col-end-5"
1225
>
13-
<div class="container-app">
14-
<slot />
15-
</div>
26+
<slot />
1627
</main>
1728

18-
<TheFooter />
29+
<!-- Right Sidebar - hidden on mobile, spans row 2-4 in column 5 on desktop -->
30+
<div
31+
id="right-sidebar"
32+
class="hidden sm:col-start-5 sm:row-start-2 sm:col-end-6 sm:row-end-5 sm:block"
33+
/>
34+
35+
<!-- Footer - full width on mobile, spans columns 2-4 on desktop -->
36+
<TheFooter class="col-span-1 row-start-5 row-end-6 sm:col-start-2 sm:col-end-5" />
1937
</div>
2038
</template>

nuxt.config.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ export default defineNuxtConfig({
4040
},
4141
},
4242
toc: {
43-
depth: 6, // Include all heading levels h1-h6
44-
searchDepth: 6, // Search through all levels
43+
depth: 5,
44+
searchDepth: 5,
4545
},
4646
},
4747
},
@@ -56,8 +56,7 @@ export default defineNuxtConfig({
5656
},
5757
},
5858
},
59-
60-
css: ['~/assets/css/main.css', '~/app.css'],
59+
css: ['~/assets/css/main.css', '~/app.css', '~/assets/css/prose-mobile.css'],
6160

6261
devtools: { enabled: true },
6362

@@ -86,7 +85,6 @@ export default defineNuxtConfig({
8685
// For better Netlify compatibility, you can optionally use Netlify's provider
8786
// provider: 'netlify',
8887
},
89-
9088
modules: [
9189
'@nuxtjs/sitemap', // Must be before @nuxt/content for v3
9290
'@nuxt/content',

0 commit comments

Comments
 (0)