Merge branch 'saicaca:main' into main
This commit is contained in:
commit
7f59fffbcd
121
astro.config.mjs
121
astro.config.mjs
@ -1,39 +1,39 @@
|
|||||||
import sitemap from '@astrojs/sitemap';
|
import sitemap from '@astrojs/sitemap'
|
||||||
import svelte from "@astrojs/svelte"
|
import svelte from '@astrojs/svelte'
|
||||||
import tailwind from "@astrojs/tailwind"
|
import tailwind from '@astrojs/tailwind'
|
||||||
import swup from '@swup/astro';
|
import swup from '@swup/astro'
|
||||||
import Compress from "astro-compress"
|
import Compress from 'astro-compress'
|
||||||
import icon from "astro-icon"
|
import icon from 'astro-icon'
|
||||||
import { defineConfig } from "astro/config"
|
import { defineConfig } from 'astro/config'
|
||||||
import Color from "colorjs.io"
|
import Color from 'colorjs.io'
|
||||||
import rehypeAutolinkHeadings from "rehype-autolink-headings"
|
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
|
||||||
import rehypeComponents from "rehype-components"; /* Render the custom directive content */
|
import rehypeComponents from 'rehype-components' /* Render the custom directive content */
|
||||||
import rehypeKatex from "rehype-katex"
|
import rehypeKatex from 'rehype-katex'
|
||||||
import rehypeSlug from "rehype-slug"
|
import rehypeSlug from 'rehype-slug'
|
||||||
import remarkDirective from "remark-directive" /* Handle directives */
|
import remarkDirective from 'remark-directive' /* Handle directives */
|
||||||
import remarkGithubAdmonitionsToDirectives from "remark-github-admonitions-to-directives";
|
import remarkGithubAdmonitionsToDirectives from 'remark-github-admonitions-to-directives'
|
||||||
import remarkMath from "remark-math"
|
import remarkMath from 'remark-math'
|
||||||
import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs"
|
import { AdmonitionComponent } from './src/plugins/rehype-component-admonition.mjs'
|
||||||
import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs"
|
import { GithubCardComponent } from './src/plugins/rehype-component-github-card.mjs'
|
||||||
import {parseDirectiveNode} from "./src/plugins/remark-directive-rehype.js";
|
import { parseDirectiveNode } from './src/plugins/remark-directive-rehype.js'
|
||||||
import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs"
|
import { remarkExcerpt } from './src/plugins/remark-excerpt.js'
|
||||||
import {remarkExcerpt} from "./src/plugins/remark-excerpt.js";
|
import { remarkReadingTime } from './src/plugins/remark-reading-time.mjs'
|
||||||
|
|
||||||
const oklchToHex = (str) => {
|
const oklchToHex = str => {
|
||||||
const DEFAULT_HUE = 250
|
const DEFAULT_HUE = 250
|
||||||
const regex = /-?\d+(\.\d+)?/g
|
const regex = /-?\d+(\.\d+)?/g
|
||||||
const matches = str.string.match(regex)
|
const matches = str.string.match(regex)
|
||||||
const lch = [matches[0], matches[1], DEFAULT_HUE]
|
const lch = [matches[0], matches[1], DEFAULT_HUE]
|
||||||
return new Color("oklch", lch).to("srgb").toString({
|
return new Color('oklch', lch).to('srgb').toString({
|
||||||
format: "hex",
|
format: 'hex',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
site: "https://fuwari.vercel.app/",
|
site: 'https://fuwari.vercel.app/',
|
||||||
base: "/",
|
base: '/',
|
||||||
trailingSlash: "always",
|
trailingSlash: 'always',
|
||||||
integrations: [
|
integrations: [
|
||||||
tailwind(),
|
tailwind(),
|
||||||
swup({
|
swup({
|
||||||
@ -41,7 +41,7 @@ export default defineConfig({
|
|||||||
animationClass: 'transition-swup-', // see https://swup.js.org/options/#animationselector
|
animationClass: 'transition-swup-', // see https://swup.js.org/options/#animationselector
|
||||||
// the default value `transition-` cause transition delay
|
// the default value `transition-` cause transition delay
|
||||||
// when the Tailwind class `transition-all` is used
|
// when the Tailwind class `transition-all` is used
|
||||||
containers: ['main'],
|
containers: ['main', '#toc'],
|
||||||
smoothScrolling: true,
|
smoothScrolling: true,
|
||||||
cache: true,
|
cache: true,
|
||||||
preload: true,
|
preload: true,
|
||||||
@ -52,10 +52,10 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
icon({
|
icon({
|
||||||
include: {
|
include: {
|
||||||
"material-symbols": ["*"],
|
'material-symbols': ['*'],
|
||||||
"fa6-brands": ["*"],
|
'fa6-brands': ['*'],
|
||||||
"fa6-regular": ["*"],
|
'fa6-regular': ['*'],
|
||||||
"fa6-solid": ["*"],
|
'fa6-solid': ['*'],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
svelte(),
|
svelte(),
|
||||||
@ -64,43 +64,53 @@ export default defineConfig({
|
|||||||
CSS: false,
|
CSS: false,
|
||||||
Image: false,
|
Image: false,
|
||||||
Action: {
|
Action: {
|
||||||
Passed: async () => true, // https://github.com/PlayForm/Compress/issues/376
|
Passed: async () => true, // https://github.com/PlayForm/Compress/issues/376
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
markdown: {
|
markdown: {
|
||||||
remarkPlugins: [remarkMath, remarkReadingTime, remarkExcerpt, remarkGithubAdmonitionsToDirectives, remarkDirective, parseDirectiveNode],
|
remarkPlugins: [
|
||||||
|
remarkMath,
|
||||||
|
remarkReadingTime,
|
||||||
|
remarkExcerpt,
|
||||||
|
remarkGithubAdmonitionsToDirectives,
|
||||||
|
remarkDirective,
|
||||||
|
parseDirectiveNode,
|
||||||
|
],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
rehypeKatex,
|
rehypeKatex,
|
||||||
rehypeSlug,
|
rehypeSlug,
|
||||||
[rehypeComponents, {
|
[
|
||||||
components: {
|
rehypeComponents,
|
||||||
github: GithubCardComponent,
|
{
|
||||||
note: (x, y) => AdmonitionComponent(x, y, "note"),
|
components: {
|
||||||
tip: (x, y) => AdmonitionComponent(x, y, "tip"),
|
github: GithubCardComponent,
|
||||||
important: (x, y) => AdmonitionComponent(x, y, "important"),
|
note: (x, y) => AdmonitionComponent(x, y, 'note'),
|
||||||
caution: (x, y) => AdmonitionComponent(x, y, "caution"),
|
tip: (x, y) => AdmonitionComponent(x, y, 'tip'),
|
||||||
warning: (x, y) => AdmonitionComponent(x, y, "warning"),
|
important: (x, y) => AdmonitionComponent(x, y, 'important'),
|
||||||
|
caution: (x, y) => AdmonitionComponent(x, y, 'caution'),
|
||||||
|
warning: (x, y) => AdmonitionComponent(x, y, 'warning'),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}],
|
],
|
||||||
[
|
[
|
||||||
rehypeAutolinkHeadings,
|
rehypeAutolinkHeadings,
|
||||||
{
|
{
|
||||||
behavior: "append",
|
behavior: 'append',
|
||||||
properties: {
|
properties: {
|
||||||
className: ["anchor"],
|
className: ['anchor'],
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
type: "element",
|
type: 'element',
|
||||||
tagName: "span",
|
tagName: 'span',
|
||||||
properties: {
|
properties: {
|
||||||
className: ["anchor-icon"],
|
className: ['anchor-icon'],
|
||||||
'data-pagefind-ignore': true,
|
'data-pagefind-ignore': true,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: 'text',
|
||||||
value: "#",
|
value: '#',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -113,12 +123,15 @@ export default defineConfig({
|
|||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
onwarn(warning, warn) {
|
onwarn(warning, warn) {
|
||||||
// temporarily suppress this warning
|
// temporarily suppress this warning
|
||||||
if (warning.message.includes("is dynamically imported by") && warning.message.includes("but also statically imported by")) {
|
if (
|
||||||
return;
|
warning.message.includes('is dynamically imported by') &&
|
||||||
|
warning.message.includes('but also statically imported by')
|
||||||
|
) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
warn(warning);
|
warn(warning)
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
"@astrojs/check": "^0.9.3",
|
"@astrojs/check": "^0.9.3",
|
||||||
"@astrojs/rss": "^4.0.7",
|
"@astrojs/rss": "^4.0.7",
|
||||||
"@astrojs/sitemap": "^3.1.6",
|
"@astrojs/sitemap": "^3.1.6",
|
||||||
"@astrojs/svelte": "^5.7.0",
|
"@astrojs/svelte": "^5.7.1",
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.1",
|
||||||
"@fontsource-variable/jetbrains-mono": "^5.0.22",
|
"@fontsource-variable/jetbrains-mono": "^5.0.22",
|
||||||
"@fontsource/roboto": "^5.0.14",
|
"@fontsource/roboto": "^5.0.14",
|
||||||
"@swup/astro": "^1.4.1",
|
"@swup/astro": "^1.4.1",
|
||||||
"astro": "^4.15.0",
|
"astro": "^4.15.9",
|
||||||
"astro-compress": "^2.3.1",
|
"astro-compress": "^2.3.1",
|
||||||
"astro-icon": "^1.1.1",
|
"astro-icon": "^1.1.1",
|
||||||
"colorjs.io": "^0.5.2",
|
"colorjs.io": "^0.5.2",
|
||||||
@ -47,7 +47,7 @@
|
|||||||
"unist-util-visit": "^5.0.0"
|
"unist-util-visit": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/ts-plugin": "^1.10.1",
|
"@astrojs/ts-plugin": "^1.10.2",
|
||||||
"@biomejs/biome": "1.8.3",
|
"@biomejs/biome": "1.8.3",
|
||||||
"@iconify-json/fa6-brands": "^1.1.22",
|
"@iconify-json/fa6-brands": "^1.1.22",
|
||||||
"@iconify-json/fa6-regular": "^1.1.22",
|
"@iconify-json/fa6-regular": "^1.1.22",
|
||||||
|
4102
pnpm-lock.yaml
generated
4102
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
225
src/base.css
Normal file
225
src/base.css
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/* The integration's default injected base.css file */
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.card-base {
|
||||||
|
@apply rounded-[var(--radius-large)] overflow-hidden bg-[var(--card-bg)] transition;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6, p, a, span, li, ul, ol, blockquote, code, pre, table, th, td, strong {
|
||||||
|
@apply transition;
|
||||||
|
}
|
||||||
|
.card-shadow {
|
||||||
|
@apply drop-shadow-[0_2px_4px_rgba(0,0,0,0.005)]
|
||||||
|
}
|
||||||
|
.expand-animation {
|
||||||
|
@apply relative before:ease-out before:transition active:bg-none hover:before:bg-[var(--btn-plain-bg-hover)] active:before:bg-[var(--btn-plain-bg-active)] z-0
|
||||||
|
before:absolute before:rounded-[inherit] before:inset-0 before:scale-[0.85] hover:before:scale-100 before:-z-10
|
||||||
|
}
|
||||||
|
.link {
|
||||||
|
@apply transition rounded-md p-1 -m-1 expand-animation;
|
||||||
|
}
|
||||||
|
.link-lg {
|
||||||
|
@apply transition rounded-md p-1.5 -m-1.5 expand-animation;
|
||||||
|
}
|
||||||
|
.float-panel {
|
||||||
|
@apply top-[5.25rem] rounded-[var(--radius-large)] overflow-hidden bg-[var(--float-panel-bg)] transition shadow-xl dark:shadow-none
|
||||||
|
}
|
||||||
|
.float-panel-closed {
|
||||||
|
@apply -translate-y-1 opacity-0 pointer-events-none
|
||||||
|
}
|
||||||
|
.search-panel mark {
|
||||||
|
@apply bg-transparent text-[var(--primary)]
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-card {
|
||||||
|
@apply transition flex items-center justify-center bg-[var(--card-bg)] hover:bg-[var(--btn-card-bg-hover)]
|
||||||
|
active:bg-[var(--btn-card-bg-active)]
|
||||||
|
}
|
||||||
|
.btn-card.disabled {
|
||||||
|
@apply pointer-events-none text-black/10 dark:text-white/10
|
||||||
|
}
|
||||||
|
.btn-plain {
|
||||||
|
@apply transition relative flex items-center justify-center bg-none
|
||||||
|
text-black/75 hover:text-[var(--primary)] dark:text-white/75 dark:hover:text-[var(--primary)];
|
||||||
|
&:not(.scale-animation) {
|
||||||
|
@apply hover:bg-[var(--btn-plain-bg-hover)] active:bg-[var(--btn-plain-bg-active)]
|
||||||
|
}
|
||||||
|
&.scale-animation {
|
||||||
|
@apply expand-animation;
|
||||||
|
&.current-theme-btn {
|
||||||
|
@apply before:scale-100 before:opacity-100 before:bg-[var(--btn-plain-bg-hover)] text-[var(--primary)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-regular {
|
||||||
|
@apply transition flex items-center justify-center bg-[var(--btn-regular-bg)] hover:bg-[var(--btn-regular-bg-hover)] active:bg-[var(--btn-regular-bg-active)]
|
||||||
|
text-[var(--btn-content)] dark:text-white/75
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-underline {
|
||||||
|
@apply transition underline decoration-2 decoration-dashed decoration-[var(--link-underline)]
|
||||||
|
hover:decoration-[var(--link-hover)] active:decoration-[var(--link-active)] underline-offset-[0.25rem]
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-hide,
|
||||||
|
.toc-not-ready {
|
||||||
|
@apply opacity-0 pointer-events-none
|
||||||
|
}
|
||||||
|
|
||||||
|
#toc-inner-wrapper {
|
||||||
|
mask-image: linear-gradient(to bottom, transparent 0%, black 2rem, black calc(100% - 2rem), transparent 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-scrollbar {
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-90 {
|
||||||
|
@apply text-black/90 dark:text-white/90
|
||||||
|
}
|
||||||
|
.text-75 {
|
||||||
|
@apply text-black/75 dark:text-white/75
|
||||||
|
}
|
||||||
|
.text-50 {
|
||||||
|
@apply text-black/50 dark:text-white/50
|
||||||
|
}
|
||||||
|
.text-30 {
|
||||||
|
@apply text-black/30 dark:text-white/30
|
||||||
|
}
|
||||||
|
.text-25 {
|
||||||
|
@apply text-black/25 dark:text-white/25
|
||||||
|
}
|
||||||
|
|
||||||
|
html.is-changing .transition-swup-fade {
|
||||||
|
@apply transition-all duration-200
|
||||||
|
}
|
||||||
|
html.is-animating .transition-swup-fade {
|
||||||
|
@apply opacity-0 translate-y-4
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PhotoSwipe */
|
||||||
|
.pswp__button {
|
||||||
|
@apply transition bg-black/40 hover:bg-black/50 active:bg-black/60 flex items-center justify-center mr-0 w-12 h-12 !important;
|
||||||
|
}
|
||||||
|
.pswp__button--zoom, .pswp__button--close {
|
||||||
|
@apply mt-4 rounded-xl active:scale-90 !important;
|
||||||
|
}
|
||||||
|
.pswp__button--zoom {
|
||||||
|
@apply mr-2.5 !important;
|
||||||
|
}
|
||||||
|
.pswp__button--close {
|
||||||
|
@apply mr-4 !important;
|
||||||
|
}
|
||||||
|
.custom-md img, #post-cover img {
|
||||||
|
@apply cursor-zoom-in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.meta-icon {
|
||||||
|
@apply w-8 h-8 transition rounded-md flex items-center justify-center bg-[var(--btn-regular-bg)]
|
||||||
|
text-[var(--btn-content)] mr-2
|
||||||
|
}
|
||||||
|
.with-divider {
|
||||||
|
@apply before:content-['/'] before:ml-1.5 before:mr-1.5 before:text-[var(--meta-divider)] before:text-sm
|
||||||
|
before:font-medium before:first-of-type:hidden before:transition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.btn-regular-dark {
|
||||||
|
@apply flex items-center justify-center
|
||||||
|
bg-[oklch(0.45_0.01_var(--hue))] hover:bg-[oklch(0.50_0.01_var(--hue))] active:bg-[oklch(0.55_0.01_var(--hue))]
|
||||||
|
dark:bg-[oklch(0.30_0.02_var(--hue))] dark:hover:bg-[oklch(0.35_0.03_var(--hue))] dark:active:bg-[oklch(0.40_0.03_var(--hue))]
|
||||||
|
}
|
||||||
|
.btn-regular-dark.success {
|
||||||
|
@apply bg-[oklch(0.75_0.14_var(--hue))] dark:bg-[oklch(0.75_0.14_var(--hue))]
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn-icon {
|
||||||
|
@apply absolute top-1/2 left-1/2 transition -translate-x-1/2 -translate-y-1/2
|
||||||
|
}
|
||||||
|
.copy-btn .copy-icon {
|
||||||
|
@apply opacity-100 fill-white dark:fill-white/75
|
||||||
|
}
|
||||||
|
.copy-btn.success .copy-icon {
|
||||||
|
@apply opacity-0 fill-[var(--deep-text)]
|
||||||
|
}
|
||||||
|
.copy-btn .success-icon {
|
||||||
|
@apply opacity-0
|
||||||
|
}
|
||||||
|
.copy-btn.success .success-icon {
|
||||||
|
@apply opacity-100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.dash-line {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-line::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 10%;
|
||||||
|
height: 100%;
|
||||||
|
top: 50%;
|
||||||
|
left: calc(50% - 1px);
|
||||||
|
border-left: 2px dashed var(--line-color);
|
||||||
|
pointer-events: none;
|
||||||
|
transition: all 0.3s;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.custom-md h1 {
|
||||||
|
@apply text-3xl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in-up {
|
||||||
|
0% {
|
||||||
|
transform: translateY(2rem);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.onload-animation {
|
||||||
|
opacity: 0;
|
||||||
|
animation: 300ms fade-in-up;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
}
|
||||||
|
#navbar {
|
||||||
|
animation-delay: 0ms
|
||||||
|
}
|
||||||
|
#sidebar {
|
||||||
|
animation-delay: 100ms
|
||||||
|
}
|
||||||
|
#swup-container {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
#content-wrapper {
|
||||||
|
animation-delay: var(--content-delay);
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
animation-delay: 250ms;
|
||||||
|
}
|
||||||
|
#banner-credit {
|
||||||
|
animation-delay: 400ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed {
|
||||||
|
height: var(--collapsedHeight);
|
||||||
|
}
|
@ -115,19 +115,4 @@ function formatTag(tag: string[]) {
|
|||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
@layer components {
|
|
||||||
.dash-line {
|
|
||||||
}
|
|
||||||
.dash-line::before {
|
|
||||||
content: "";
|
|
||||||
@apply w-[10%] h-full absolute -top-1/2 left-[calc(50%_-_1px)] -top-[50%] border-l-[2px]
|
|
||||||
border-dashed pointer-events-none border-[var(--line-color)] transition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -49,9 +49,6 @@ rainbow-dark = linear-gradient(to right, oklch(0.70 0.10 0), oklch(0.70 0.10 30)
|
|||||||
:root
|
:root
|
||||||
--radius-large 1rem
|
--radius-large 1rem
|
||||||
|
|
||||||
--banner-height-home 65vh
|
|
||||||
--banner-height 35vh
|
|
||||||
|
|
||||||
--content-delay 150ms
|
--content-delay 150ms
|
||||||
|
|
||||||
color_set({
|
color_set({
|
||||||
@ -120,6 +117,10 @@ color_set({
|
|||||||
--admonitions-color-important: oklch(0.7 0.14 310) oklch(0.75 0.14 310)
|
--admonitions-color-important: oklch(0.7 0.14 310) oklch(0.75 0.14 310)
|
||||||
--admonitions-color-warning: oklch(0.7 0.14 60) oklch(0.75 0.14 60)
|
--admonitions-color-warning: oklch(0.7 0.14 60) oklch(0.75 0.14 60)
|
||||||
--admonitions-color-caution: oklch(0.6 0.2 25) oklch(0.65 0.2 25)
|
--admonitions-color-caution: oklch(0.6 0.2 25) oklch(0.65 0.2 25)
|
||||||
|
|
||||||
|
--toc-badge-bg: oklch(0.9 0.045 var(--hue)) var(--btn-regular-bg)
|
||||||
|
--toc-btn-hover: oklch(0.92 0.015 var(--hue)) oklch(0.22 0.02 var(--hue))
|
||||||
|
--toc-btn-active: oklch(0.90 0.015 var(--hue)) oklch(0.25 0.02 var(--hue))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -176,143 +177,4 @@ color_set({
|
|||||||
--os-handle-bg-active: var(--scrollbar-bg-active-light);
|
--os-handle-bg-active: var(--scrollbar-bg-active-light);
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<style is:global lang="scss">
|
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
@layer components {
|
|
||||||
.card-base {
|
|
||||||
@apply rounded-[var(--radius-large)] overflow-hidden bg-[var(--card-bg)] transition;
|
|
||||||
}
|
|
||||||
h1, h2, h3, h4, h5, h6, p, a, span, li, ul, ol, blockquote, code, pre, table, th, td, strong {
|
|
||||||
@apply transition;
|
|
||||||
}
|
|
||||||
.card-shadow {
|
|
||||||
@apply drop-shadow-[0_2px_4px_rgba(0,0,0,0.005)]
|
|
||||||
}
|
|
||||||
.expand-animation {
|
|
||||||
@apply relative before:ease-out before:transition active:bg-none hover:before:bg-[var(--btn-plain-bg-hover)] active:before:bg-[var(--btn-plain-bg-active)] z-0
|
|
||||||
before:absolute before:rounded-[inherit] before:inset-0 before:scale-[0.85] hover:before:scale-100 before:-z-10
|
|
||||||
}
|
|
||||||
.link {
|
|
||||||
@apply transition rounded-md p-1 -m-1 expand-animation;
|
|
||||||
}
|
|
||||||
.link-lg {
|
|
||||||
@apply transition rounded-md p-1.5 -m-1.5 expand-animation;
|
|
||||||
}
|
|
||||||
.float-panel {
|
|
||||||
@apply top-[5.25rem] rounded-[var(--radius-large)] overflow-hidden bg-[var(--float-panel-bg)] transition shadow-xl dark:shadow-none
|
|
||||||
}
|
|
||||||
.float-panel-closed {
|
|
||||||
@apply -translate-y-1 opacity-0 pointer-events-none
|
|
||||||
}
|
|
||||||
.search-panel mark {
|
|
||||||
@apply bg-transparent text-[var(--primary)]
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-card {
|
|
||||||
@apply transition flex items-center justify-center bg-[var(--card-bg)] hover:bg-[var(--btn-card-bg-hover)]
|
|
||||||
active:bg-[var(--btn-card-bg-active)]
|
|
||||||
}
|
|
||||||
.btn-card.disabled {
|
|
||||||
@apply pointer-events-none text-black/10 dark:text-white/10
|
|
||||||
}
|
|
||||||
.btn-plain {
|
|
||||||
@apply transition relative flex items-center justify-center bg-none
|
|
||||||
text-black/75 hover:text-[var(--primary)] dark:text-white/75 dark:hover:text-[var(--primary)];
|
|
||||||
&:not(.scale-animation) {
|
|
||||||
@apply hover:bg-[var(--btn-plain-bg-hover)] active:bg-[var(--btn-plain-bg-active)]
|
|
||||||
}
|
|
||||||
&.scale-animation {
|
|
||||||
@apply expand-animation;
|
|
||||||
&.current-theme-btn {
|
|
||||||
@apply before:scale-100 before:opacity-100 before:bg-[var(--btn-plain-bg-hover)] text-[var(--primary)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.btn-regular {
|
|
||||||
@apply transition flex items-center justify-center bg-[var(--btn-regular-bg)] hover:bg-[var(--btn-regular-bg-hover)] active:bg-[var(--btn-regular-bg-active)]
|
|
||||||
text-[var(--btn-content)] dark:text-white/75
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-underline {
|
|
||||||
@apply transition underline decoration-2 decoration-dashed decoration-[var(--link-underline)]
|
|
||||||
hover:decoration-[var(--link-hover)] active:decoration-[var(--link-active)] underline-offset-[0.25rem]
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-90 {
|
|
||||||
@apply text-black/90 dark:text-white/90
|
|
||||||
}
|
|
||||||
.text-75 {
|
|
||||||
@apply text-black/75 dark:text-white/75
|
|
||||||
}
|
|
||||||
.text-50 {
|
|
||||||
@apply text-black/50 dark:text-white/50
|
|
||||||
}
|
|
||||||
.text-30 {
|
|
||||||
@apply text-black/30 dark:text-white/30
|
|
||||||
}
|
|
||||||
.text-25 {
|
|
||||||
@apply text-black/25 dark:text-white/25
|
|
||||||
}
|
|
||||||
|
|
||||||
html.is-changing .transition-swup-fade {
|
|
||||||
@apply transition-all duration-200
|
|
||||||
}
|
|
||||||
html.is-animating .transition-swup-fade {
|
|
||||||
@apply opacity-0 translate-y-4
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PhotoSwipe */
|
|
||||||
.pswp__button {
|
|
||||||
@apply transition bg-black/40 hover:bg-black/50 active:bg-black/60 flex items-center justify-center mr-0 w-12 h-12 !important;
|
|
||||||
}
|
|
||||||
.pswp__button--zoom, .pswp__button--close {
|
|
||||||
@apply mt-4 rounded-xl active:scale-90 !important;
|
|
||||||
}
|
|
||||||
.pswp__button--zoom {
|
|
||||||
@apply mr-2.5 !important;
|
|
||||||
}
|
|
||||||
.pswp__button--close {
|
|
||||||
@apply mr-4 !important;
|
|
||||||
}
|
|
||||||
.custom-md img, #post-cover img {
|
|
||||||
@apply cursor-zoom-in
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-in-up {
|
|
||||||
0% {
|
|
||||||
transform: translateY(2rem);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateY(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onload-animation {
|
|
||||||
opacity: 0;
|
|
||||||
animation: 300ms fade-in-up;
|
|
||||||
animation-fill-mode: forwards;
|
|
||||||
}
|
|
||||||
#navbar {
|
|
||||||
animation-delay: 0ms
|
|
||||||
}
|
|
||||||
#sidebar {
|
|
||||||
animation-delay: 100ms
|
|
||||||
}
|
|
||||||
#content-wrapper {
|
|
||||||
animation-delay: var(--content-delay);
|
|
||||||
}
|
|
||||||
.footer {
|
|
||||||
animation-delay: 250ms;
|
|
||||||
}
|
|
||||||
#banner-credit {
|
|
||||||
animation-delay: 400ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -67,9 +67,6 @@ let links: NavBarLink[] = navBarConfig.links.map(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="stylus">
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
function switchTheme() {
|
function switchTheme() {
|
||||||
|
@ -59,19 +59,4 @@ const className = Astro.props.class
|
|||||||
{!(tags && tags.length > 0) && <div class="transition text-50 text-sm font-medium">{i18n(I18nKey.noTags)}</div>}
|
{!(tags && tags.length > 0) && <div class="transition text-50 text-sm font-medium">{i18n(I18nKey.noTags)}</div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
|
||||||
@tailwind components;
|
|
||||||
|
|
||||||
@layer components {
|
|
||||||
.meta-icon {
|
|
||||||
@apply w-8 h-8 transition rounded-md flex items-center justify-center bg-[var(--btn-regular-bg)]
|
|
||||||
text-[var(--btn-content)] mr-2
|
|
||||||
}
|
|
||||||
.with-divider {
|
|
||||||
@apply before:content-['/'] before:ml-1.5 before:mr-1.5 before:text-[var(--meta-divider)] before:text-sm
|
|
||||||
before:font-medium before:first-of-type:hidden before:transition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -117,3 +117,9 @@ top-20 left-4 md:left-[unset] right-4 shadow-2xl rounded-2xl p-2">
|
|||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -25,7 +25,7 @@ import { Icon } from 'astro-icon/components'
|
|||||||
font-weight: bold
|
font-weight: bold
|
||||||
border: none
|
border: none
|
||||||
position: fixed
|
position: fixed
|
||||||
bottom: 15rem
|
bottom: 10rem
|
||||||
opacity: 1
|
opacity: 1
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
transform: translateX(5rem)
|
transform: translateX(5rem)
|
||||||
|
@ -7,7 +7,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
const className = Astro.props.class
|
const className = Astro.props.class
|
||||||
---
|
---
|
||||||
<div data-pagefind-body class=`prose dark:prose-invert prose-base max-w-none custom-md ${className}`>
|
<div data-pagefind-body class=`prose dark:prose-invert prose-base !max-w-none custom-md ${className}`>
|
||||||
<!--<div class="prose dark:prose-invert max-w-none custom-md">-->
|
<!--<div class="prose dark:prose-invert max-w-none custom-md">-->
|
||||||
<!--<div class="max-w-none custom-md">-->
|
<!--<div class="max-w-none custom-md">-->
|
||||||
<slot/>
|
<slot/>
|
||||||
@ -65,40 +65,6 @@ const className = Astro.props.class
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Styles for copy-code-button -->
|
|
||||||
<style lang="css" is:global>
|
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
@layer components {
|
|
||||||
.btn-regular-dark {
|
|
||||||
@apply flex items-center justify-center
|
|
||||||
bg-[oklch(0.45_0.01_var(--hue))] hover:bg-[oklch(0.50_0.01_var(--hue))] active:bg-[oklch(0.55_0.01_var(--hue))]
|
|
||||||
dark:bg-[oklch(0.30_0.02_var(--hue))] dark:hover:bg-[oklch(0.35_0.03_var(--hue))] dark:active:bg-[oklch(0.40_0.03_var(--hue))]
|
|
||||||
}
|
|
||||||
.btn-regular-dark.success {
|
|
||||||
@apply bg-[oklch(0.75_0.14_var(--hue))] dark:bg-[oklch(0.75_0.14_var(--hue))]
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy-btn-icon {
|
|
||||||
@apply absolute top-1/2 left-1/2 transition -translate-x-1/2 -translate-y-1/2
|
|
||||||
}
|
|
||||||
.copy-btn .copy-icon {
|
|
||||||
@apply opacity-100 fill-white dark:fill-white/75
|
|
||||||
}
|
|
||||||
.copy-btn.success .copy-icon {
|
|
||||||
@apply opacity-0 fill-[var(--deep-text)]
|
|
||||||
}
|
|
||||||
.copy-btn .success-icon {
|
|
||||||
@apply opacity-0
|
|
||||||
}
|
|
||||||
.copy-btn.success .success-icon {
|
|
||||||
@apply opacity-100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="stylus" is:global>
|
<style lang="stylus" is:global>
|
||||||
.custom-md
|
.custom-md
|
||||||
h1, h2, h3, h4, h5, h6
|
h1, h2, h3, h4, h5, h6
|
||||||
@ -475,17 +441,4 @@ const className = Astro.props.class
|
|||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1)
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1)
|
||||||
transition-duration: 0.15s
|
transition-duration: 0.15s
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="css" is:global>
|
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
@layer components {
|
|
||||||
.custom-md h1 {
|
|
||||||
@apply text-3xl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -2,8 +2,17 @@
|
|||||||
import Profile from './Profile.astro'
|
import Profile from './Profile.astro'
|
||||||
import Tag from './Tags.astro'
|
import Tag from './Tags.astro'
|
||||||
import Categories from './Categories.astro'
|
import Categories from './Categories.astro'
|
||||||
|
import type { MarkdownHeading } from 'astro'
|
||||||
|
import TOC from './TOC.astro'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
class? : string
|
||||||
|
headings? : MarkdownHeading[]
|
||||||
|
}
|
||||||
|
|
||||||
const className = Astro.props.class
|
const className = Astro.props.class
|
||||||
|
const headings = Astro.props.headings
|
||||||
|
|
||||||
---
|
---
|
||||||
<div id="sidebar" class:list={[className, "w-full"]}>
|
<div id="sidebar" class:list={[className, "w-full"]}>
|
||||||
<div class="flex flex-col w-full gap-4 mb-4">
|
<div class="flex flex-col w-full gap-4 mb-4">
|
||||||
|
75
src/components/widget/TOC.astro
Normal file
75
src/components/widget/TOC.astro
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
import type { MarkdownHeading } from 'astro';
|
||||||
|
import { siteConfig } from "../../config";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
class?: string
|
||||||
|
headings: MarkdownHeading[]
|
||||||
|
}
|
||||||
|
|
||||||
|
let { headings = [] } = Astro.props;
|
||||||
|
|
||||||
|
// generate random headings, for testing
|
||||||
|
// headings = [
|
||||||
|
// { text: 'Heading 1', depth: 1, slug: 'heading-1' },
|
||||||
|
// { text: 'Heading 2', depth: 2, slug: 'heading-2' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 2', depth: 2, slug: 'heading-2' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 1', depth: 1, slug: 'heading-1' },
|
||||||
|
// { text: 'Heading 2', depth: 2, slug: 'heading-2' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 2', depth: 2, slug: 'heading-2' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// { text: 'Heading 3', depth: 3, slug: 'heading-3' },
|
||||||
|
// ]
|
||||||
|
|
||||||
|
let minDepth = 10;
|
||||||
|
for (const heading of headings) {
|
||||||
|
minDepth = Math.min(minDepth, heading.depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
const className = Astro.props.class
|
||||||
|
|
||||||
|
const removeTailingHash = (text: string) => {
|
||||||
|
let lastIndexOfHash = text.lastIndexOf('#');
|
||||||
|
if (lastIndexOfHash != text.length - 1) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.substring(0, lastIndexOfHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
let heading1Count = 1;
|
||||||
|
|
||||||
|
const maxLevel = siteConfig.toc.depth;
|
||||||
|
---
|
||||||
|
<div class:list={[className]}>
|
||||||
|
{headings.filter((heading) => heading.depth < minDepth + maxLevel).map((heading) =>
|
||||||
|
<a href={`#${heading.slug}`} class="px-2 flex gap-2 relative transition w-full min-h-9 rounded-xl
|
||||||
|
hover:bg-[var(--toc-btn-hover)] active:bg-[var(--toc-btn-active)] py-2
|
||||||
|
">
|
||||||
|
<div class:list={["w-5 h-5 shrink-0 rounded-lg text-xs flex items-center justify-center font-bold",
|
||||||
|
{
|
||||||
|
"bg-[var(--toc-badge-bg)] text-[var(--btn-content)]": heading.depth == minDepth,
|
||||||
|
"ml-4": heading.depth == minDepth + 1,
|
||||||
|
"ml-8": heading.depth == minDepth + 2,
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{heading.depth == minDepth && heading1Count++}
|
||||||
|
{heading.depth == minDepth + 1 && <div class="w-2 h-2 rounded-[0.1875rem] bg-[var(--toc-badge-bg)]"></div>}
|
||||||
|
{heading.depth == minDepth + 2 && <div class="w-1.5 h-1.5 rounded-sm bg-black/5 dark:bg-white/10"></div>}
|
||||||
|
</div>
|
||||||
|
<div class:list={["text-sm", {
|
||||||
|
"text-50": heading.depth == minDepth || heading.depth == minDepth + 1,
|
||||||
|
"text-30": heading.depth == minDepth + 2,
|
||||||
|
}]}>{removeTailingHash(heading.text)}</div>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
@ -24,6 +24,10 @@ export const siteConfig: SiteConfig = {
|
|||||||
url: '' // (Optional) URL link to the original artwork or artist's page
|
url: '' // (Optional) URL link to the original artwork or artist's page
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
toc: {
|
||||||
|
enable: true, // Display the table of contents on the right side of the post
|
||||||
|
depth: 2 // Maximum heading depth to show in the table, from 1 to 3
|
||||||
|
},
|
||||||
favicon: [ // Leave this array empty to use the default favicon
|
favicon: [ // Leave this array empty to use the default favicon
|
||||||
// {
|
// {
|
||||||
// src: '/favicon/icon.png', // Path of the favicon, relative to the /public directory
|
// src: '/favicon/icon.png', // Path of the favicon, relative to the /public directory
|
||||||
|
@ -3,6 +3,17 @@ export const UNCATEGORIZED = '__uncategorized__'
|
|||||||
export const PAGE_SIZE = 8
|
export const PAGE_SIZE = 8
|
||||||
|
|
||||||
export const LIGHT_MODE = 'light',
|
export const LIGHT_MODE = 'light',
|
||||||
DARK_MODE = 'dark',
|
DARK_MODE = 'dark',
|
||||||
AUTO_MODE = 'auto'
|
AUTO_MODE = 'auto'
|
||||||
export const DEFAULT_THEME = AUTO_MODE
|
export const DEFAULT_THEME = AUTO_MODE
|
||||||
|
|
||||||
|
// Banner height unit: vh
|
||||||
|
export const BANNER_HEIGHT = 35
|
||||||
|
export const BANNER_HEIGHT_EXTEND = 30
|
||||||
|
export const BANNER_HEIGHT_HOME = BANNER_HEIGHT + BANNER_HEIGHT_EXTEND
|
||||||
|
|
||||||
|
// The height the main panel overlaps the banner, unit: rem
|
||||||
|
export const MAIN_PANEL_OVERLAPS_BANNER_HEIGHT = 3.5
|
||||||
|
|
||||||
|
// Page width: rem
|
||||||
|
export const PAGE_WIDTH = 75
|
@ -8,7 +8,7 @@ category: 'Examples'
|
|||||||
draft: true
|
draft: true
|
||||||
---
|
---
|
||||||
|
|
||||||
## GitHub repository cards
|
## GitHub Repository Cards
|
||||||
You can add dynamic cards that link to GitHub repositories, on page load, the repository information is pulled from the GitHub API.
|
You can add dynamic cards that link to GitHub repositories, on page load, the repository information is pulled from the GitHub API.
|
||||||
|
|
||||||
::github{repo="Fabrizz/MMM-OnSpotify"}
|
::github{repo="Fabrizz/MMM-OnSpotify"}
|
||||||
@ -43,6 +43,8 @@ Critical content demanding immediate user attention due to potential risks.
|
|||||||
Negative potential consequences of an action.
|
Negative potential consequences of an action.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
### Basic Syntax
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
:::note
|
:::note
|
||||||
Highlights information that users should take into account, even when skimming.
|
Highlights information that users should take into account, even when skimming.
|
||||||
@ -53,6 +55,8 @@ Optional information to help a user be more successful.
|
|||||||
:::
|
:::
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Custom Titles
|
||||||
|
|
||||||
The title of the admonition can be customized.
|
The title of the admonition can be customized.
|
||||||
|
|
||||||
:::note[MY CUSTOM TITLE]
|
:::note[MY CUSTOM TITLE]
|
||||||
@ -65,6 +69,8 @@ This is a note with a custom title.
|
|||||||
:::
|
:::
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### GitHub Syntax
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> [The GitHub syntax](https://github.com/orgs/community/discussions/16925) is also supported.
|
> [The GitHub syntax](https://github.com/orgs/community/discussions/16925) is also supported.
|
||||||
|
|
||||||
|
@ -12,6 +12,10 @@ import {
|
|||||||
DARK_MODE,
|
DARK_MODE,
|
||||||
DEFAULT_THEME,
|
DEFAULT_THEME,
|
||||||
LIGHT_MODE,
|
LIGHT_MODE,
|
||||||
|
BANNER_HEIGHT,
|
||||||
|
BANNER_HEIGHT_EXTEND,
|
||||||
|
BANNER_HEIGHT_HOME,
|
||||||
|
PAGE_WIDTH,
|
||||||
} from '../constants/constants'
|
} from '../constants/constants'
|
||||||
import { defaultFavicons } from '../constants/icon'
|
import { defaultFavicons } from '../constants/icon'
|
||||||
import type { Favicon } from '../types/config'
|
import type { Favicon } from '../types/config'
|
||||||
@ -61,12 +65,12 @@ if (!lang) {
|
|||||||
const siteLang = lang.replace('_', '-')
|
const siteLang = lang.replace('_', '-')
|
||||||
|
|
||||||
const bannerOffsetByPosition = {
|
const bannerOffsetByPosition = {
|
||||||
'top': '30vh',
|
top: `${BANNER_HEIGHT_EXTEND}vh`,
|
||||||
'center': '15vh',
|
center: `${BANNER_HEIGHT_EXTEND / 2}vh`,
|
||||||
'bottom': '0'
|
bottom: '0',
|
||||||
}
|
}
|
||||||
const bannerOffset = bannerOffsetByPosition[siteConfig.banner.position || 'center']
|
const bannerOffset =
|
||||||
|
bannerOffsetByPosition[siteConfig.banner.position || 'center']
|
||||||
---
|
---
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -105,8 +109,14 @@ const bannerOffset = bannerOffsetByPosition[siteConfig.banner.position || 'cente
|
|||||||
media={favicon.theme && `(prefers-color-scheme: ${favicon.theme})`}
|
media={favicon.theme && `(prefers-color-scheme: ${favicon.theme})`}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
<style define:vars={{
|
||||||
|
configHue,
|
||||||
|
'page-width': `${PAGE_WIDTH}rem`,
|
||||||
|
}}></style> <!-- defines global css variables. This will be applied to <html> <body> and some other elements idk why -->
|
||||||
|
|
||||||
<!-- Set the theme before the page is rendered to avoid a flash -->
|
<!-- Set the theme before the page is rendered to avoid a flash -->
|
||||||
<script is:inline define:vars={{DEFAULT_THEME: DEFAULT_THEME, LIGHT_MODE: LIGHT_MODE, DARK_MODE: DARK_MODE, AUTO_MODE: AUTO_MODE}}>
|
<script is:inline define:vars={{DEFAULT_THEME, LIGHT_MODE, DARK_MODE, AUTO_MODE, BANNER_HEIGHT_EXTEND, PAGE_WIDTH}}>
|
||||||
const theme = localStorage.getItem('theme') || DEFAULT_THEME;
|
const theme = localStorage.getItem('theme') || DEFAULT_THEME;
|
||||||
switch (theme) {
|
switch (theme) {
|
||||||
case LIGHT_MODE:
|
case LIGHT_MODE:
|
||||||
@ -122,6 +132,17 @@ const bannerOffset = bannerOffsetByPosition[siteConfig.banner.position || 'cente
|
|||||||
document.documentElement.classList.remove('dark');
|
document.documentElement.classList.remove('dark');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculate the --banner-height-extend, which needs to be a multiple of 4 to avoid blurry text
|
||||||
|
let offset = Math.floor(window.innerHeight * (BANNER_HEIGHT_EXTEND / 100));
|
||||||
|
offset = offset - offset % 4;
|
||||||
|
document.documentElement.style.setProperty('--banner-height-extend', `${offset}px`);
|
||||||
|
|
||||||
|
// calculate the width of TOC widget
|
||||||
|
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize)
|
||||||
|
const mainGridWidthPx = PAGE_WIDTH * rootFontSize
|
||||||
|
const tocWidth = (window.innerWidth - mainGridWidthPx) / 2 - rootFontSize
|
||||||
|
document.documentElement.style.setProperty('--toc-width', `${tocWidth}px`);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot name="head"></slot>
|
<slot name="head"></slot>
|
||||||
@ -130,20 +151,12 @@ const bannerOffset = bannerOffsetByPosition[siteConfig.banner.position || 'cente
|
|||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title={profileConfig.name} href={`${Astro.site}rss.xml`}/>
|
<link rel="alternate" type="application/rss+xml" title={profileConfig.name} href={`${Astro.site}rss.xml`}/>
|
||||||
|
|
||||||
<style define:vars={{ configHue }}></style> <!-- defines global css variables. This will be applied to <html> <body> and some other elements idk why -->
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body class=" min-h-screen transition " class:list={[{"lg:is-home": isHomePage, "enable-banner": enableBanner}]}
|
<body class=" min-h-screen transition " class:list={[{"lg:is-home": isHomePage, "enable-banner": enableBanner}]}
|
||||||
data-overlayscrollbars-initialize
|
data-overlayscrollbars-initialize
|
||||||
>
|
>
|
||||||
<ConfigCarrier></ConfigCarrier>
|
<ConfigCarrier></ConfigCarrier>
|
||||||
<GlobalStyles>
|
<GlobalStyles>
|
||||||
{siteConfig.banner.enable && <div id="banner-wrapper" class="absolute -top-[30vh] w-full transition duration-700 overflow-hidden">
|
|
||||||
<ImageWrapper id="banner" alt="Banner image of the blog" class:list={["object-cover h-full transition duration-700 opacity-0 scale-105"]}
|
|
||||||
src={siteConfig.banner.src} position={siteConfig.banner.position}
|
|
||||||
>
|
|
||||||
</ImageWrapper>
|
|
||||||
</div>}
|
|
||||||
<slot />
|
<slot />
|
||||||
</GlobalStyles>
|
</GlobalStyles>
|
||||||
|
|
||||||
@ -151,19 +164,22 @@ const bannerOffset = bannerOffsetByPosition[siteConfig.banner.position || 'cente
|
|||||||
<div id="page-height-extend" class="hidden h-[300vh]"></div>
|
<div id="page-height-extend" class="hidden h-[300vh]"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
:root {
|
:root {
|
||||||
--hue: var(--configHue);
|
--hue: var(--configHue);
|
||||||
--page-width: 75rem;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style is:global define:vars={{ bannerOffset }}>
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
|
<style is:global define:vars={{
|
||||||
|
bannerOffset,
|
||||||
|
'banner-height-home': `${BANNER_HEIGHT_HOME}vh`,
|
||||||
|
'banner-height': `${BANNER_HEIGHT}vh`,
|
||||||
|
}}>
|
||||||
|
@tailwind components;
|
||||||
@layer components {
|
@layer components {
|
||||||
.enable-banner.is-home #banner-wrapper {
|
.enable-banner.is-home #banner-wrapper {
|
||||||
@apply h-[var(--banner-height-home)] translate-y-[30vh]
|
@apply h-[var(--banner-height-home)] translate-y-[var(--banner-height-extend)]
|
||||||
}
|
}
|
||||||
.enable-banner #banner-wrapper {
|
.enable-banner #banner-wrapper {
|
||||||
@apply h-[var(--banner-height-home)]
|
@apply h-[var(--banner-height-home)]
|
||||||
@ -176,19 +192,20 @@ const bannerOffset = bannerOffsetByPosition[siteConfig.banner.position || 'cente
|
|||||||
@apply h-[var(--banner-height-home)] translate-y-[var(--bannerOffset)]
|
@apply h-[var(--banner-height-home)] translate-y-[var(--bannerOffset)]
|
||||||
}
|
}
|
||||||
.enable-banner.is-home #main-grid {
|
.enable-banner.is-home #main-grid {
|
||||||
@apply translate-y-[30vh];
|
@apply translate-y-[var(--banner-height-extend)];
|
||||||
}
|
}
|
||||||
.enable-banner #top-row {
|
.enable-banner #top-row {
|
||||||
@apply h-[calc(var(--banner-height-home)_-_4.5rem)] transition-all duration-300
|
@apply h-[calc(var(--banner-height-home)_-_4.5rem)] transition-all duration-300
|
||||||
}
|
}
|
||||||
.enable-banner.is-home #sidebar-sticky {
|
.enable-banner.is-home #sidebar-sticky {
|
||||||
@apply top-[calc(-30vh_+_1rem)]
|
@apply top-[calc(1rem_-_var(--banner-height-extend))]
|
||||||
}
|
}
|
||||||
.navbar-hidden {
|
.navbar-hidden {
|
||||||
@apply opacity-0 -translate-y-16
|
@apply opacity-0 -translate-y-16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
import {
|
import {
|
||||||
@ -199,8 +216,15 @@ import {
|
|||||||
} from 'overlayscrollbars';
|
} from 'overlayscrollbars';
|
||||||
import {getHue, getStoredTheme, setHue, setTheme} from "../utils/setting-utils";
|
import {getHue, getStoredTheme, setHue, setTheme} from "../utils/setting-utils";
|
||||||
import {pathsEqual, url} from "../utils/url-utils";
|
import {pathsEqual, url} from "../utils/url-utils";
|
||||||
|
import {
|
||||||
|
BANNER_HEIGHT,
|
||||||
|
BANNER_HEIGHT_HOME,
|
||||||
|
BANNER_HEIGHT_EXTEND,
|
||||||
|
MAIN_PANEL_OVERLAPS_BANNER_HEIGHT,
|
||||||
|
PAGE_WIDTH
|
||||||
|
} from "../constants/constants";
|
||||||
|
|
||||||
/* Preload fonts */
|
/* Preload fonts */
|
||||||
// (async function() {
|
// (async function() {
|
||||||
// try {
|
// try {
|
||||||
// await Promise.all([
|
// await Promise.all([
|
||||||
@ -342,15 +366,15 @@ const setup = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
// Remove the delay for the first time page load
|
|
||||||
window.swup.hooks.on('link:click', () => {
|
window.swup.hooks.on('link:click', () => {
|
||||||
|
// Remove the delay for the first time page load
|
||||||
document.documentElement.style.setProperty('--content-delay', '0ms')
|
document.documentElement.style.setProperty('--content-delay', '0ms')
|
||||||
|
|
||||||
// prevent elements from overlapping the navbar
|
// prevent elements from overlapping the navbar
|
||||||
if (!bannerEnabled) {
|
if (!bannerEnabled) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let threshold = window.innerHeight * 0.30 - 72 - 16
|
let threshold = window.innerHeight * (BANNER_HEIGHT / 100) - 72 - 16
|
||||||
let navbar = document.getElementById('navbar-wrapper')
|
let navbar = document.getElementById('navbar-wrapper')
|
||||||
if (!navbar || !document.body.classList.contains('lg:is-home')) {
|
if (!navbar || !document.body.classList.contains('lg:is-home')) {
|
||||||
return
|
return
|
||||||
@ -374,6 +398,12 @@ const setup = () => {
|
|||||||
if (heightExtend) {
|
if (heightExtend) {
|
||||||
heightExtend.classList.remove('hidden')
|
heightExtend.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide the TOC while scrolling back to top
|
||||||
|
let toc = document.getElementById('toc-wrapper');
|
||||||
|
if (toc) {
|
||||||
|
toc.classList.add('toc-not-ready')
|
||||||
|
}
|
||||||
});
|
});
|
||||||
window.swup.hooks.on('page:view', () => {
|
window.swup.hooks.on('page:view', () => {
|
||||||
// hide the temp high element when the transition is done
|
// hide the temp high element when the transition is done
|
||||||
@ -383,11 +413,18 @@ const setup = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
window.swup.hooks.on('visit:end', (visit: {to: {url: string}}) => {
|
window.swup.hooks.on('visit:end', (visit: {to: {url: string}}) => {
|
||||||
// execute 1s later
|
setTimeout(() => {
|
||||||
const heightExtend = document.getElementById('page-height-extend')
|
const heightExtend = document.getElementById('page-height-extend')
|
||||||
if (heightExtend) {
|
if (heightExtend) {
|
||||||
heightExtend.classList.add('hidden')
|
heightExtend.classList.add('hidden')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Just make the transition looks better
|
||||||
|
const toc = document.getElementById('toc-wrapper');
|
||||||
|
if (toc) {
|
||||||
|
toc.classList.remove('toc-not-ready')
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (window?.swup?.hooks) {
|
if (window?.swup?.hooks) {
|
||||||
@ -397,22 +434,37 @@ if (window?.swup?.hooks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let backToTopBtn = document.getElementById('back-to-top-btn');
|
let backToTopBtn = document.getElementById('back-to-top-btn');
|
||||||
|
let toc = document.getElementById('toc-wrapper');
|
||||||
let navbar = document.getElementById('navbar-wrapper')
|
let navbar = document.getElementById('navbar-wrapper')
|
||||||
function scrollFunction() {
|
function scrollFunction() {
|
||||||
|
let bannerHeight = window.innerHeight * (BANNER_HEIGHT / 100)
|
||||||
|
|
||||||
if (backToTopBtn) {
|
if (backToTopBtn) {
|
||||||
if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
|
if (document.body.scrollTop > bannerHeight || document.documentElement.scrollTop > bannerHeight) {
|
||||||
backToTopBtn.classList.remove('hide')
|
backToTopBtn.classList.remove('hide')
|
||||||
} else {
|
} else {
|
||||||
backToTopBtn.classList.add('hide')
|
backToTopBtn.classList.add('hide')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bannerEnabled && toc) {
|
||||||
|
if (document.body.scrollTop > bannerHeight || document.documentElement.scrollTop > bannerHeight) {
|
||||||
|
toc.classList.remove('toc-hide')
|
||||||
|
} else {
|
||||||
|
toc.classList.add('toc-hide')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!bannerEnabled) return
|
if (!bannerEnabled) return
|
||||||
if (navbar) {
|
if (navbar) {
|
||||||
let threshold = window.innerHeight * 0.30 - 72 - 16
|
const NAVBAR_HEIGHT = 72
|
||||||
|
const MAIN_PANEL_EXCESS_HEIGHT = MAIN_PANEL_OVERLAPS_BANNER_HEIGHT * 16 // The height the main panel overlaps the banner
|
||||||
|
|
||||||
|
let bannerHeight = BANNER_HEIGHT
|
||||||
if (document.body.classList.contains('lg:is-home') && window.innerWidth >= 1024) {
|
if (document.body.classList.contains('lg:is-home') && window.innerWidth >= 1024) {
|
||||||
threshold = window.innerHeight * 0.60 - 72 - 16
|
bannerHeight = BANNER_HEIGHT_HOME
|
||||||
}
|
}
|
||||||
|
let threshold = window.innerHeight * (bannerHeight / 100) - NAVBAR_HEIGHT - MAIN_PANEL_EXCESS_HEIGHT - 16
|
||||||
if (document.body.scrollTop >= threshold || document.documentElement.scrollTop >= threshold) {
|
if (document.body.scrollTop >= threshold || document.documentElement.scrollTop >= threshold) {
|
||||||
navbar.classList.add('navbar-hidden')
|
navbar.classList.add('navbar-hidden')
|
||||||
} else {
|
} else {
|
||||||
@ -422,6 +474,19 @@ function scrollFunction() {
|
|||||||
}
|
}
|
||||||
window.onscroll = scrollFunction
|
window.onscroll = scrollFunction
|
||||||
|
|
||||||
|
window.onresize = () => {
|
||||||
|
// calculate the --banner-height-extend, which needs to be a multiple of 4 to avoid blurry text
|
||||||
|
let offset = Math.floor(window.innerHeight * (BANNER_HEIGHT_EXTEND / 100));
|
||||||
|
offset = offset - offset % 4;
|
||||||
|
document.documentElement.style.setProperty('--banner-height-extend', `${offset}px`);
|
||||||
|
|
||||||
|
// calculate the width of TOC widget
|
||||||
|
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize)
|
||||||
|
const mainGridWidthPx = PAGE_WIDTH * rootFontSize
|
||||||
|
const tocWidth = (window.innerWidth - mainGridWidthPx) / 2 - rootFontSize
|
||||||
|
document.documentElement.style.setProperty('--toc-width', `${tocWidth}px`);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -6,6 +6,10 @@ import SideBar from '@components/widget/SideBar.astro'
|
|||||||
import Layout from './Layout.astro'
|
import Layout from './Layout.astro'
|
||||||
import { Icon } from 'astro-icon/components'
|
import { Icon } from 'astro-icon/components'
|
||||||
import { siteConfig } from '../config'
|
import { siteConfig } from '../config'
|
||||||
|
import type { MarkdownHeading } from 'astro'
|
||||||
|
import TOC from "../components/widget/TOC.astro";
|
||||||
|
import ImageWrapper from "../components/misc/ImageWrapper.astro";
|
||||||
|
import {BANNER_HEIGHT, BANNER_HEIGHT_EXTEND, MAIN_PANEL_OVERLAPS_BANNER_HEIGHT} from "../constants/constants";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title?: string
|
title?: string
|
||||||
@ -13,15 +17,20 @@ interface Props {
|
|||||||
description?: string
|
description?: string
|
||||||
lang?: string
|
lang?: string
|
||||||
setOGTypeArticle?: boolean;
|
setOGTypeArticle?: boolean;
|
||||||
|
headings? : MarkdownHeading[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, banner, description, lang, setOGTypeArticle } = Astro.props
|
const { title, banner, description, lang, setOGTypeArticle, headings = [] } = Astro.props
|
||||||
const hasBannerCredit =
|
const hasBannerCredit =
|
||||||
siteConfig.banner.enable && siteConfig.banner.credit.enable
|
siteConfig.banner.enable && siteConfig.banner.credit.enable
|
||||||
const hasBannerLink = !!siteConfig.banner.credit.url
|
const hasBannerLink = !!siteConfig.banner.credit.url
|
||||||
|
|
||||||
|
const mainPanelTop = siteConfig.banner.enable ? `calc(${BANNER_HEIGHT}vh - ${MAIN_PANEL_OVERLAPS_BANNER_HEIGHT}rem)` : "5.5rem"
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={title} banner={banner} description={description} lang={lang} setOGTypeArticle={setOGTypeArticle}>
|
<Layout title={title} banner={banner} description={description} lang={lang} setOGTypeArticle={setOGTypeArticle}>
|
||||||
|
|
||||||
|
<!-- Navbar -->
|
||||||
<slot slot="head" name="head"></slot>
|
<slot slot="head" name="head"></slot>
|
||||||
<div id="top-row" class="z-50 pointer-events-none relative transition-all duration-700 max-w-[var(--page-width)] px-0 md:px-4 mx-auto" class:list={[""]}>
|
<div id="top-row" class="z-50 pointer-events-none relative transition-all duration-700 max-w-[var(--page-width)] px-0 md:px-4 mx-auto" class:list={[""]}>
|
||||||
<div id="navbar-wrapper" class="pointer-events-auto sticky top-0 transition-all">
|
<div id="navbar-wrapper" class="pointer-events-auto sticky top-0 transition-all">
|
||||||
@ -29,8 +38,18 @@ const hasBannerLink = !!siteConfig.banner.credit.url
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="absolute w-full" class:list={[{"top-[30vh]": siteConfig.banner.enable, "top-[5.5rem]": !siteConfig.banner.enable}]}>
|
<!-- Banner -->
|
||||||
<div class="relative max-w-[var(--page-width)] mx-auto">
|
{siteConfig.banner.enable && <div id="banner-wrapper" class=`absolute z-10 w-full transition duration-700 overflow-hidden` style=`top: -${BANNER_HEIGHT_EXTEND}vh`>
|
||||||
|
<ImageWrapper id="banner" alt="Banner image of the blog" class:list={["object-cover h-full transition duration-700 opacity-0 scale-105"]}
|
||||||
|
src={siteConfig.banner.src} position={siteConfig.banner.position}
|
||||||
|
>
|
||||||
|
</ImageWrapper>
|
||||||
|
</div>}
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<div class="absolute w-full z-30 pointer-events-none" style=`top: ${mainPanelTop}`>
|
||||||
|
<!-- The pointer-events-none here prevent blocking the click event of the TOC -->
|
||||||
|
<div class="relative max-w-[var(--page-width)] mx-auto pointer-events-auto">
|
||||||
<div id="main-grid" class="transition duration-700 w-full left-0 right-0 grid grid-cols-[17.5rem_auto] grid-rows-[auto_1fr_auto] lg:grid-rows-[auto]
|
<div id="main-grid" class="transition duration-700 w-full left-0 right-0 grid grid-cols-[17.5rem_auto] grid-rows-[auto_1fr_auto] lg:grid-rows-[auto]
|
||||||
mx-auto gap-4 px-0 md:px-4"
|
mx-auto gap-4 px-0 md:px-4"
|
||||||
>
|
>
|
||||||
@ -48,7 +67,7 @@ const hasBannerLink = !!siteConfig.banner.credit.url
|
|||||||
</a>}
|
</a>}
|
||||||
|
|
||||||
|
|
||||||
<SideBar class="mb-4 row-start-2 row-end-3 col-span-2 lg:row-start-1 lg:row-end-2 lg:col-span-1 lg:max-w-[17.5rem] onload-animation"></SideBar>
|
<SideBar class="mb-4 row-start-2 row-end-3 col-span-2 lg:row-start-1 lg:row-end-2 lg:col-span-1 lg:max-w-[17.5rem] onload-animation" headings={headings}></SideBar>
|
||||||
|
|
||||||
<main id="swup-container" class="transition-swup-fade col-span-2 lg:col-span-1 overflow-hidden">
|
<main id="swup-container" class="transition-swup-fade col-span-2 lg:col-span-1 overflow-hidden">
|
||||||
<div id="content-wrapper" class="onload-animation">
|
<div id="content-wrapper" class="onload-animation">
|
||||||
@ -65,7 +84,29 @@ const hasBannerLink = !!siteConfig.banner.credit.url
|
|||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BackToTop></BackToTop>
|
<BackToTop></BackToTop>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- The things that should be under the banner, only the TOC for now -->
|
||||||
|
<div class="absolute w-full z-0">
|
||||||
|
<div class="relative max-w-[var(--page-width)] mx-auto">
|
||||||
|
<!-- TOC component -->
|
||||||
|
{siteConfig.toc.enable && <div id="toc-wrapper" class:list={["transition absolute top-0 -right-[var(--toc-width)] w-[var(--toc-width)] flex items-center",
|
||||||
|
{"toc-hide": siteConfig.banner.enable}]}
|
||||||
|
>
|
||||||
|
<div id="toc-inner-wrapper" class="fixed top-14 w-[var(--toc-width)] h-[calc(100vh_-_20rem)] overflow-y-scroll overflow-x-hidden hide-scrollbar">
|
||||||
|
<div id="toc" class="w-full h-full transition-swup-fade ">
|
||||||
|
<div class="h-8 w-full"></div>
|
||||||
|
<TOC headings={headings}></TOC>
|
||||||
|
<div class="h-8 w-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
|
|
||||||
|
<!-- #toc needs to exist for Swup to work normally -->
|
||||||
|
{!siteConfig.toc.enable && <div id="toc"></div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -25,7 +25,7 @@ export async function getStaticPaths() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { entry } = Astro.props
|
const { entry } = Astro.props
|
||||||
const { Content } = await entry.render()
|
const { Content, headings } = await entry.render()
|
||||||
|
|
||||||
const { remarkPluginFrontmatter } = await entry.render()
|
const { remarkPluginFrontmatter } = await entry.render()
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ const jsonLd = {
|
|||||||
// TODO include cover image here
|
// TODO include cover image here
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
<MainGridLayout banner={entry.data.image} title={entry.data.title} description={entry.data.description} lang={entry.data.lang} setOGTypeArticle={true}>
|
<MainGridLayout banner={entry.data.image} title={entry.data.title} description={entry.data.description} lang={entry.data.lang} setOGTypeArticle={true} headings={headings}>
|
||||||
<script is:inline slot="head" type="application/ld+json" set:html={JSON.stringify(jsonLd)}></script>
|
<script is:inline slot="head" type="application/ld+json" set:html={JSON.stringify(jsonLd)}></script>
|
||||||
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative mb-4">
|
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative mb-4">
|
||||||
<div id="post-container" class:list={["card-base z-10 px-6 md:px-9 pt-6 pb-4 relative w-full ",
|
<div id="post-container" class:list={["card-base z-10 px-6 md:px-9 pt-6 pb-4 relative w-full ",
|
||||||
@ -72,7 +72,7 @@ const jsonLd = {
|
|||||||
<div
|
<div
|
||||||
data-pagefind-body data-pagefind-weight="10" data-pagefind-meta="title"
|
data-pagefind-body data-pagefind-weight="10" data-pagefind-meta="title"
|
||||||
class="transition w-full block font-bold mb-3
|
class="transition w-full block font-bold mb-3
|
||||||
text-3xl md:text-[2.5rem]/[2.75rem]
|
text-3xl md:text-[2.25rem]/[2.75rem]
|
||||||
text-black/90 dark:text-white/90
|
text-black/90 dark:text-white/90
|
||||||
md:before:w-1 before:h-5 before:rounded-md before:bg-[var(--primary)]
|
md:before:w-1 before:h-5 before:rounded-md before:bg-[var(--primary)]
|
||||||
before:absolute before:top-[0.75rem] before:left-[-1.125rem]
|
before:absolute before:top-[0.75rem] before:left-[-1.125rem]
|
||||||
|
@ -20,6 +20,10 @@ export type SiteConfig = {
|
|||||||
url?: string
|
url?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
toc: {
|
||||||
|
enable: boolean
|
||||||
|
depth: 1 | 2 | 3
|
||||||
|
}
|
||||||
|
|
||||||
favicon: Favicon[]
|
favicon: Favicon[]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user