feat: post styles, next/prev post btn, display-settings, etc.
(cherry picked from commit b7ddd92729d52a8c43d72010b743f7e3477f1001)
This commit is contained in:
parent
8ed0aa071f
commit
26408b0b7e
|
@ -12,7 +12,6 @@
|
|||
"dependencies": {
|
||||
"@astrojs/check": "^0.2.0",
|
||||
"@astrojs/tailwind": "^4.0.0",
|
||||
"@astrojs/ts-plugin": "^1.1.3",
|
||||
"@fontsource/roboto": "^5.0.8",
|
||||
"astro": "^3.0.10",
|
||||
"astro-icon": "^1.0.0-next.2",
|
||||
|
@ -23,6 +22,7 @@
|
|||
"typescript": "^5.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/ts-plugin": "^1.1.3",
|
||||
"@iconify-json/fa6-brands": "^1.1.13",
|
||||
"@iconify-json/material-symbols": "^1.1.57",
|
||||
"@rollup/plugin-yaml": "^4.1.1",
|
||||
|
|
|
@ -11,9 +11,6 @@ dependencies:
|
|||
'@astrojs/tailwind':
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0(astro@3.0.10)(tailwindcss@3.3.3)
|
||||
'@astrojs/ts-plugin':
|
||||
specifier: ^1.1.3
|
||||
version: 1.1.3
|
||||
'@fontsource/roboto':
|
||||
specifier: ^5.0.8
|
||||
version: 5.0.8
|
||||
|
@ -40,6 +37,9 @@ dependencies:
|
|||
version: 5.2.2
|
||||
|
||||
devDependencies:
|
||||
'@astrojs/ts-plugin':
|
||||
specifier: ^1.1.3
|
||||
version: 1.1.3
|
||||
'@iconify-json/fa6-brands':
|
||||
specifier: ^1.1.13
|
||||
version: 1.1.13
|
||||
|
@ -103,7 +103,6 @@ packages:
|
|||
|
||||
/@astrojs/compiler@1.5.7:
|
||||
resolution: {integrity: sha512-dFU7GAMbpTUGPkRoCoMQrGFlTe3qIiQMSOxIXp/nB1Do4My9uogjEmBHdR5Cwr4i6rc5/1R3Od9v8kU/pkHXGQ==}
|
||||
dev: false
|
||||
|
||||
/@astrojs/compiler@2.0.1:
|
||||
resolution: {integrity: sha512-DfBR7Cf+tOgQ4n7TIgTtU5x5SEA/08DNshpEPcT+91A0KbBlmUOYMBM/O6qAaHkmVo1KIoXQYhAmfdTT1zx9PQ==}
|
||||
|
@ -216,7 +215,7 @@ packages:
|
|||
'@volar/language-core': 1.10.1
|
||||
'@volar/typescript': 1.10.1
|
||||
vscode-languageserver-textdocument: 1.0.8
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/@babel/code-frame@7.22.13:
|
||||
resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==}
|
||||
|
@ -1117,7 +1116,6 @@ packages:
|
|||
resolution: {integrity: sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA==}
|
||||
dependencies:
|
||||
'@volar/source-map': 1.10.1
|
||||
dev: false
|
||||
|
||||
/@volar/language-server@1.10.1:
|
||||
resolution: {integrity: sha512-UXgRMAPKoy4EZBcBT1SFp8YIb5AJqe7Is1/TnqRUq0LBBV2M7HpEeHHI8E4fy05Eg4TlSVRcrlZtiTrY9fRjJg==}
|
||||
|
@ -1148,13 +1146,11 @@ packages:
|
|||
resolution: {integrity: sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA==}
|
||||
dependencies:
|
||||
muggle-string: 0.3.1
|
||||
dev: false
|
||||
|
||||
/@volar/typescript@1.10.1:
|
||||
resolution: {integrity: sha512-+iiO9yUSRHIYjlteT+QcdRq8b44qH19/eiUZtjNtuh6D9ailYM7DVR0zO2sEgJlvCaunw/CF9Ov2KooQBpR4VQ==}
|
||||
dependencies:
|
||||
'@volar/language-core': 1.10.1
|
||||
dev: false
|
||||
|
||||
/@vscode/emmet-helper@2.9.2:
|
||||
resolution: {integrity: sha512-MaGuyW+fa13q3aYsluKqclmh62Hgp0BpKIqS66fCxfOaBcVQ1OnMQxRRgQUYnCkxFISAQlkJ0qWWPyXjro1Qrg==}
|
||||
|
@ -3029,7 +3025,6 @@ packages:
|
|||
|
||||
/muggle-string@0.3.1:
|
||||
resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
|
||||
dev: false
|
||||
|
||||
/mz@2.7.0:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
|
@ -4328,7 +4323,6 @@ packages:
|
|||
|
||||
/vscode-languageserver-textdocument@1.0.8:
|
||||
resolution: {integrity: sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==}
|
||||
dev: false
|
||||
|
||||
/vscode-languageserver-types@3.17.3:
|
||||
resolution: {integrity: sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==}
|
||||
|
|
|
@ -69,7 +69,7 @@ function formatDate(date: Date) {
|
|||
</div>
|
||||
{group.posts.map(post => (
|
||||
<a href={getPostUrlBySlug(post.slug)} class="group">
|
||||
<Button light height="40px" class="w-full hover:text-[initial]">
|
||||
<Button light height="40px" class="w-full rounded-lg hover:text-[initial]">
|
||||
<div class="flex flex-row justify-start items-center h-full">
|
||||
<!-- date -->
|
||||
<div class="w-[10%] transition text-sm text-right text-black/50 dark:text-white/50">{formatDate(post.data.pubDate)}</div>
|
||||
|
|
|
@ -43,6 +43,9 @@ color_set(colors)
|
|||
if length(value) > 1
|
||||
{key}: oklch_fallback(value[1])
|
||||
|
||||
rainbow-light = linear-gradient(to right, oklch(0.80 0.10 0), oklch(0.80 0.10 30), oklch(0.80 0.10 60), oklch(0.80 0.10 90), oklch(0.80 0.10 120), oklch(0.80 0.10 150), oklch(0.80 0.10 180), oklch(0.80 0.10 210), oklch(0.80 0.10 240), oklch(0.80 0.10 270), oklch(0.80 0.10 300), oklch(0.80 0.10 330), oklch(0.80 0.10 360))
|
||||
rainbow-dark = linear-gradient(to right, oklch(0.70 0.10 0), oklch(0.70 0.10 30), oklch(0.70 0.10 60), oklch(0.70 0.10 90), oklch(0.70 0.10 120), oklch(0.70 0.10 150), oklch(0.70 0.10 180), oklch(0.70 0.10 210), oklch(0.70 0.10 240), oklch(0.70 0.10 270), oklch(0.70 0.10 300), oklch(0.70 0.10 330), oklch(0.70 0.10 360))
|
||||
|
||||
:root
|
||||
--radius-large 16px
|
||||
|
||||
|
@ -53,7 +56,7 @@ color_set({
|
|||
--primary: oklch(0.70 0.14 var(--hue))
|
||||
--card-bg: white oklch(0.25 0.02 var(--hue))
|
||||
|
||||
--btn-content: oklch(0.55 0.12 var(--hue))
|
||||
--btn-content: oklch(0.55 0.12 var(--hue)) oklch(0.75 0.1 var(--hue))
|
||||
|
||||
--btn-regular-bg: oklch(0.95 0.025 var(--hue)) oklch(0.38 0.04 var(--hue))
|
||||
|
||||
|
@ -70,6 +73,8 @@ color_set({
|
|||
--line-color: black(0.1) white(0.1)
|
||||
--meta-divider: black(0.2) white(0.2)
|
||||
--selection-bg: oklch(0.90 0.05 var(--hue)) oklch(0.40 0.08 var(--hue))
|
||||
|
||||
--color-selection-bar: rainbow-light rainbow-dark
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
---
|
||||
import Button from "./control/Button.astro";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import DisplaySetting from "./widget/DisplaySetting.astro";
|
||||
const className = Astro.props.class;
|
||||
---
|
||||
<div class:list={[
|
||||
className,
|
||||
"card-base max-w-[var(--page-width)] h-[72px] rounded-t-none mx-auto flex items-center justify-between px-4"]}>
|
||||
<a href="/"><Button height="52px" class="px-5 font-bold" light>
|
||||
<a href="/"><Button height="52px" class="px-5 font-bold rounded-lg" light>
|
||||
<div class="flex flex-row text-[var(--primary)] items-center text-md">
|
||||
<Icon name="material-symbols:home-outline-rounded" size={28} class="mb-1 mr-2" />
|
||||
<div class="top-2"></div>Vivia Preview
|
||||
</div>
|
||||
</Button></a>
|
||||
<div>
|
||||
<a href="/"><Button light class="font-bold px-5">Home</Button></a>
|
||||
<a href="/archive"><Button light class="font-bold px-5">Archive</Button></a>
|
||||
<a href="/about"><Button light class="font-bold px-5">About</Button></a>
|
||||
<a href="/"><Button light class="font-bold px-5 rounded-lg">Home</Button></a>
|
||||
<a href="/archive"><Button light class="font-bold px-5 rounded-lg">Archive</Button></a>
|
||||
<a href="/about"><Button light class="font-bold px-5 rounded-lg">About</Button></a>
|
||||
</div>
|
||||
<div>
|
||||
<Button id="scheme-switch" iconName="material-symbols:wb-sunny-outline-rounded" iconSize={20} isIcon light></Button>
|
||||
<div class="flex">
|
||||
<div>
|
||||
<Button class="rounded-lg" id="display-settings-switch" iconName="material-symbols:palette-outline" iconSize={20} isIcon light></Button>
|
||||
</div>
|
||||
<div>
|
||||
<Button class="rounded-lg" id="scheme-switch" iconName="material-symbols:wb-sunny-outline-rounded" iconSize={20} isIcon light></Button>
|
||||
</div>
|
||||
</div>
|
||||
<DisplaySetting></DisplaySetting>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -40,13 +47,15 @@ function switchTheme() {
|
|||
|
||||
function loadThemeSwitchScript() {
|
||||
let switchBtn = document.getElementById("scheme-switch");
|
||||
if (switchBtn === null) {
|
||||
console.log("test")
|
||||
}
|
||||
switchBtn.addEventListener("click", function () {
|
||||
console.log("test")
|
||||
switchTheme()
|
||||
});
|
||||
|
||||
let settingBtn = document.getElementById("display-settings-switch");
|
||||
settingBtn.addEventListener("click", function () {
|
||||
let settingPanel = document.getElementById("display-setting");
|
||||
settingPanel.classList.toggle("closed");
|
||||
});
|
||||
}
|
||||
|
||||
loadThemeSwitchScript();
|
||||
|
|
|
@ -68,7 +68,7 @@ const className = Astro.props.class;
|
|||
@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)] dark:text-[var(--primary)] mr-2
|
||||
text-[var(--btn-content)] mr-2
|
||||
}
|
||||
.with-divider {
|
||||
@apply before:content-['/'] before:mx-[6px] before:text-[var(--meta-divider)] before:text-sm
|
||||
|
|
|
@ -43,7 +43,7 @@ const { remarkPluginFrontmatter } = await entry.render();
|
|||
</a>
|
||||
|
||||
<!-- metadata -->
|
||||
<PostMetadata pubDate={pubDate} tags={tags} categories={categories} class="mb-4"></PostMetadata>
|
||||
<PostMetadata pubDate={pubDate} tags={tags} categories={categories} class:list={{"mb-4": description, "mb-6": !description}}></PostMetadata>
|
||||
|
||||
<div class="transition text-black/75 dark:text-white/75 mb-4">
|
||||
{ description }
|
||||
|
@ -67,7 +67,7 @@ const { remarkPluginFrontmatter } = await entry.render();
|
|||
<Icon name="material-symbols:chevron-right-rounded"
|
||||
class="transition opacity-0 group-hover:opacity-100 text-white text-5xl"></Icon>
|
||||
</div>
|
||||
<ImageBox src="https://saicaca.github.io/vivia-preview/assets/79905307_p0.jpg"
|
||||
<ImageBox src={cover}
|
||||
class="w-full h-full">
|
||||
</ImageBox>
|
||||
</a>}
|
||||
|
|
|
@ -5,7 +5,7 @@ import Button from "./Button.astro";
|
|||
|
||||
<!-- There can't be a filter on parent element, or it will break `fixed` -->
|
||||
<div class="back-to-top-wrapper" transition:persist>
|
||||
<div id="back-to-top-btn" class="back-to-top-btn hide flex items-center rounded-2xl overflow-hidden" onclick="topFunction()">
|
||||
<div id="back-to-top-btn" class="back-to-top-btn hide flex items-center rounded-2xl overflow-hidden transition" onclick="topFunction()">
|
||||
<Button card height="60px" width="60px">
|
||||
<Icon name="material-symbols:keyboard-arrow-up-rounded" class="mx-auto"></Icon>
|
||||
</Button>
|
||||
|
|
|
@ -34,7 +34,6 @@ import { Icon } from 'astro-icon/components';
|
|||
class:list={[
|
||||
className,
|
||||
`
|
||||
rounded-lg
|
||||
transition
|
||||
h-[var(--height)]
|
||||
`,
|
||||
|
@ -60,7 +59,7 @@ import { Icon } from 'astro-icon/components';
|
|||
'dark:hover:bg-[oklch(0.45_0.045_var(--hue))]': regular,
|
||||
'dark:active:bg-[oklch(0.5_0.05_var(--hue))]': regular,
|
||||
|
||||
'card-base': card,
|
||||
'bg-[var(--card-bg)]': card,
|
||||
'enabled:hover:bg-[var(--btn-card-bg-hover)]': card,
|
||||
'enabled:active:bg-[var(--btn-card-bg-active)]': card,
|
||||
'disabled:text-black/10': card,
|
||||
|
|
|
@ -8,7 +8,7 @@ interface Props {
|
|||
const { size, dot, href }: Props = Astro.props;
|
||||
---
|
||||
<a href={href}>
|
||||
<Button regular height="32px" class="text-[15px] px-3 flex flex-row items-center">
|
||||
<Button regular height="32px" class="text-[15px] px-3 flex flex-row items-center rounded-lg">
|
||||
{dot && <div class="h-1 w-1 bg-[var(--btn-content)] dark:bg-[var(--card-bg)] transition rounded-md mr-2"></div>}
|
||||
<slot></slot>
|
||||
</Button>
|
||||
|
|
|
@ -55,7 +55,7 @@ const commonUrl: string = parts.slice(0, -1).join('/') + '/';
|
|||
|
||||
<div class:list={[className, "flex flex-row gap-3 justify-center"]}>
|
||||
<a href={page.url.prev}>
|
||||
<Button isIcon card iconName="material-symbols:chevron-left-rounded" class="text-[var(--primary)]" iconSize={28}
|
||||
<Button isIcon card iconName="material-symbols:chevron-left-rounded" class="text-[var(--primary)] rounded-lg" iconSize={28}
|
||||
disabled = {page.url.prev == undefined}
|
||||
></Button>
|
||||
</a>
|
||||
|
@ -70,14 +70,14 @@ const commonUrl: string = parts.slice(0, -1).join('/') + '/';
|
|||
{p}
|
||||
</div>
|
||||
return <a href={commonUrl + p}>
|
||||
<Button card iconName="material-symbols:chevron-left-rounded" height="44px" width="44px">
|
||||
<Button card iconName="material-symbols:chevron-left-rounded" class="rounded-lg" height="44px" width="44px">
|
||||
{p}
|
||||
</Button>
|
||||
</a>
|
||||
})}
|
||||
</div>
|
||||
<a href={page.url.next}>
|
||||
<Button isIcon card iconName="material-symbols:chevron-right-rounded" class="text-[var(--primary)]" iconSize={28}
|
||||
<Button isIcon card iconName="material-symbols:chevron-right-rounded" class="text-[var(--primary)] rounded-lg" iconSize={28}
|
||||
disabled = {page.url.next == undefined}
|
||||
></Button>
|
||||
</a>
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
import {getConfig} from "../../utils/config-utils";
|
||||
const hueSet: number[] = [0, 30, 60, 180, 250, 270, 300, 330, 345];
|
||||
|
||||
const enableBanner = getConfig().banner.enable;
|
||||
|
||||
---
|
||||
<div id="display-setting" class:list={["card-base closed absolute transition-all w-[320px] fixed right-4 border-[var(--primary)] px-4 py-4",
|
||||
{"border-[3px]": !enableBanner}
|
||||
]}>
|
||||
<div class="flex flex-row gap-2 mb-3 items-center justify-between">
|
||||
<div class="font-bold text-lg text-neutral-900 dark:text-neutral-100 transition relative ml-3
|
||||
before:w-1 before:h-4 before:rounded-md before:bg-[var(--primary)]
|
||||
before:absolute before:left-[-12px] before:top-[5.5px]"
|
||||
>
|
||||
Primary Color
|
||||
</div>
|
||||
<div id="hueValue" class="transition bg-[var(--btn-regular-bg)] w-10 h-7 rounded-md flex justify-center font-bold transition text-sm items-center text-[var(--btn-content)]">
|
||||
{0}
|
||||
</div>
|
||||
</div>
|
||||
<div id="preset-list" class="flex flex-row gap-1 mb-4 hidden">
|
||||
{hueSet.map((hue) => <div
|
||||
class="h-7 w-8 rounded-md cursor-pointer
|
||||
bg-[oklch(0.75_0.14_var(--hue))]
|
||||
hover:bg-[oklch(0.70_0.12_var(--hue))]
|
||||
active:bg-[oklch(0.65_0.11_var(--hue))]
|
||||
"
|
||||
style=`--hue: ${hue}` data-hue={hue}
|
||||
>
|
||||
|
||||
</div>)}
|
||||
</div>
|
||||
<div class="w-full h-6 px-1 bg-[oklch(0.80_0.10_0)] dark:bg-[oklch(0.70_0.10_0)] rounded select-none">
|
||||
<input type="range" min="0" max="360" value="0" class="slider" id="colorSlider" step="5" style="width: 100%;">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script is:raw>
|
||||
(function () {
|
||||
let presetList = document.getElementById("preset-list");
|
||||
let output = document.getElementById("hueValue");
|
||||
let slider = document.getElementById("colorSlider");
|
||||
output.innerHTML = slider.value; // Display the default slider value
|
||||
|
||||
let r = document.querySelector(':root');
|
||||
function setHue(hue) {
|
||||
localStorage.setItem('hue', hue);
|
||||
output.innerHTML = hue;
|
||||
slider.value = hue;
|
||||
|
||||
r.style.setProperty(`--hue`, hue);
|
||||
}
|
||||
|
||||
let storedHue = localStorage.getItem('hue');
|
||||
if (storedHue) {
|
||||
setHue(storedHue);
|
||||
}
|
||||
|
||||
presetList.onclick = function(event) {
|
||||
let hue = event.target.dataset.hue;
|
||||
if (hue) {
|
||||
setHue(hue);
|
||||
}
|
||||
}
|
||||
|
||||
slider.oninput = function() {
|
||||
let hue = this.value;
|
||||
output.innerHTML = this.value;
|
||||
setHue(hue);
|
||||
}
|
||||
|
||||
document.addEventListener("click", event => {
|
||||
var cDom = document.getElementById("display-setting");
|
||||
let settingBtn = document.getElementById("display-settings-switch");
|
||||
var tDom = event.target;
|
||||
if (cDom == tDom || cDom.contains(tDom) || settingBtn == tDom || settingBtn.contains(tDom)) {
|
||||
return;
|
||||
}
|
||||
cDom.classList.add("closed");
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus" is:global>
|
||||
#display-setting
|
||||
input[type="range"]
|
||||
-webkit-appearance: none;
|
||||
height: 24px;
|
||||
background-image: var(--color-selection-bar)
|
||||
transition: background-image 0.15s ease-in-out
|
||||
|
||||
/* Input Thumb */
|
||||
::-webkit-slider-thumb
|
||||
-webkit-appearance: none;
|
||||
height: 16px;
|
||||
width: 8px;
|
||||
border-radius: 2px;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
box-shadow: none;
|
||||
|
||||
::-moz-range-thumb
|
||||
-webkit-appearance: none;
|
||||
height: 24px;
|
||||
width: 10px;
|
||||
border-radius: 4px;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
box-shadow: none;
|
||||
|
||||
&::-ms-thumb
|
||||
-webkit-appearance: none;
|
||||
height: 24px;
|
||||
width: 10px;
|
||||
border-radius: 4px;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
box-shadow: none;
|
||||
</style>
|
||||
|
||||
<style>
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
#display-setting {
|
||||
@apply top-[84px]
|
||||
}
|
||||
#display-setting.closed {
|
||||
@apply top-[76px] opacity-0 pointer-events-none
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import ImageBox from "../misc/ImageBox.astro";
|
||||
import ButtonLight from "../control/Button.astro";
|
||||
import Button from "../control/Button.astro";
|
||||
import {getConfig} from "../../utils/config-utils";
|
||||
interface props {
|
||||
|
||||
|
@ -18,7 +18,7 @@ const vConf = getConfig();
|
|||
<div class="flex gap-2 mx-2 justify-center mb-4">
|
||||
{vConf.profile.links.map(item =>
|
||||
<a href={item.url} target="_blank">
|
||||
<ButtonLight isIcon iconName={item.icon} regular height="40px"></ButtonLight>
|
||||
<Button isIcon iconName={item.icon} regular height="40px" class="rounded-lg"></Button>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -46,11 +46,14 @@ const myFade = {
|
|||
// defines global css variables
|
||||
// why doing this in Layout instead of GlobalStyles: https://github.com/withastro/astro/issues/6728#issuecomment-1502203757
|
||||
const viConf = getConfig();
|
||||
const hue = viConf.appearance.hue;
|
||||
const configHue = viConf.appearance.hue;
|
||||
if (!banner || typeof banner !== 'string' || banner.trim() === '') {
|
||||
banner = viConf.banner.url;
|
||||
}
|
||||
|
||||
// TODO don't use post cover as banner for now
|
||||
banner = viConf.banner.url;
|
||||
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
@ -71,7 +74,7 @@ if (!banner || typeof banner !== 'string' || banner.trim() === '') {
|
|||
<link rel="icon" media="(prefers-color-scheme: dark)" href="/favicon/favicon-dark-180.png" sizes="180x180">
|
||||
<link rel="icon" media="(prefers-color-scheme: dark)" href="/favicon/favicon-dark-192.png" sizes="192x192">
|
||||
|
||||
<style define:vars={{ hue }}></style> <!-- defines global css variables -->
|
||||
<style define:vars={{ configHue }}></style> <!-- defines global css variables. This will be applied to <html> <body> and some other elements idk why -->
|
||||
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
|
@ -82,7 +85,7 @@ if (!banner || typeof banner !== 'string' || banner.trim() === '') {
|
|||
id="banner-wrapper"
|
||||
>
|
||||
<!-- TODO the transition here is not correct -->
|
||||
<ImageBox id="boxtest" class="object-center object-cover h-full"
|
||||
<ImageBox id="boxtest" class:list={["object-center object-cover h-full", {"hidden": !viConf.banner.enable}]}
|
||||
src={banner} transition:animate="fade"
|
||||
>
|
||||
</ImageBox>
|
||||
|
@ -93,6 +96,7 @@ if (!banner || typeof banner !== 'string' || banner.trim() === '') {
|
|||
</html>
|
||||
<style is:global>
|
||||
:root {
|
||||
--hue: var(--configHue);
|
||||
--accent: 136, 58, 234;
|
||||
--accent-light: 224, 204, 250;
|
||||
--accent-dark: 49, 10, 101;
|
||||
|
@ -169,7 +173,13 @@ function loadTheme() {
|
|||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
}
|
||||
loadTheme();
|
||||
|
||||
function loadHue() {
|
||||
const hue = localStorage.hue;
|
||||
if (hue) {
|
||||
document.documentElement.style.setProperty('--hue', hue);
|
||||
}
|
||||
}
|
||||
|
||||
function setBannerHeight() {
|
||||
const banner = document.getElementById('banner-wrapper');
|
||||
|
@ -182,10 +192,15 @@ function setBannerHeight() {
|
|||
}
|
||||
}
|
||||
|
||||
/* Load light/dark mode setting */
|
||||
/* Load settings when entering the site */
|
||||
loadTheme();
|
||||
loadHue();
|
||||
|
||||
/* Load settings before swapping */
|
||||
/* astro:after-swap event happened before swap animation */
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
setBannerHeight();
|
||||
loadTheme();
|
||||
loadHue();
|
||||
}, { once: false });
|
||||
</script>
|
|
@ -5,10 +5,12 @@ import SideBar from "../components/widget/SideBar.astro";
|
|||
import {pathsEqual} from "../utils/url-utils";
|
||||
import Footer from "../components/Footer.astro";
|
||||
import BackToTop from "../components/control/BackToTop.astro";
|
||||
import DisplaySetting from "../components/widget/DisplaySetting.astro";
|
||||
import {getConfig} from "../utils/config-utils";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
banner: string;
|
||||
banner?: string;
|
||||
}
|
||||
|
||||
const { title, banner } = Astro.props;
|
||||
|
@ -18,14 +20,16 @@ const isHomePage = pathsEqual(Astro.url.pathname, '/') || pathsEqual(Astro.url.p
|
|||
const pageWidth = "1200px";
|
||||
const sidebarWidth = "280px";
|
||||
|
||||
const enableBanner = getConfig().banner.enable;
|
||||
|
||||
---
|
||||
<Layout title={title} banner={banner}>
|
||||
<div class=`max-w-[1200px] min-h-screen grid grid-cols-[280px_auto] grid-rows-[auto_auto_1fr_auto] lg:grid-rows-[auto_1fr_auto] mx-auto gap-4 relative overflow-hidden `
|
||||
transition:animate="none"
|
||||
>
|
||||
<div id="top-row" class="col-span-2 grid-rows-1" class:list={{
|
||||
'min-h-[calc(var(--banner-height-home)_-_72px)]': isHomePage,
|
||||
'min-h-[calc(var(--banner-height)_-_72px)]': !isHomePage}}
|
||||
<div id="top-row" class="col-span-2 grid-rows-1 z-50" class:list={{
|
||||
'min-h-[calc(var(--banner-height-home)_-_72px)]': enableBanner && isHomePage,
|
||||
'min-h-[calc(var(--banner-height)_-_72px)]': enableBanner && !isHomePage,}}
|
||||
>
|
||||
<Navbar transition:animate="fade" transition:persist></Navbar>
|
||||
</div>
|
||||
|
@ -37,8 +41,8 @@ const sidebarWidth = "280px";
|
|||
|
||||
</div>
|
||||
|
||||
<div class="grid-rows-3 col-span-2 mt-4" transition:persist>
|
||||
<Footer></Footer>
|
||||
<div class="grid-rows-3 col-span-2 mt-4" transition:persist transition:animate="fade">
|
||||
<Footer transition:persist></Footer>
|
||||
</div>
|
||||
<BackToTop></BackToTop>
|
||||
</div>
|
||||
|
|
|
@ -6,8 +6,9 @@ import ImageBox from "../../components/misc/ImageBox.astro";
|
|||
import {Icon} from "astro-icon/components";
|
||||
import {formatDateToYYYYMMDD} from "../../utils/date-utils";
|
||||
import PostMetadata from "../../components/PostMetadata.astro";
|
||||
// 1. 为每个集合条目生成一个新路径
|
||||
|
||||
import {getPostUrlBySlug} from "../../utils/content-utils";
|
||||
import Button from "../../components/control/Button.astro";
|
||||
import {getConfig} from "../../utils/config-utils";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const blogEntries = await getCollection('posts');
|
||||
|
@ -15,16 +16,17 @@ export async function getStaticPaths() {
|
|||
params: { slug: entry.slug }, props: { entry },
|
||||
}));
|
||||
}
|
||||
// 2. 当渲染的时候,你可以直接从属性中得到条目
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const { Content } = await entry.render();
|
||||
|
||||
const { remarkPluginFrontmatter } = await entry.render();
|
||||
|
||||
const enableBanner = getConfig().banner.enable;
|
||||
|
||||
---
|
||||
<MainGridLayout banner={entry.data.cover}>
|
||||
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative">
|
||||
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative mb-4">
|
||||
<div class:list={["card-base z-10 px-9 py-6 relative w-full ",
|
||||
{}
|
||||
]}>
|
||||
|
@ -59,15 +61,39 @@ const { remarkPluginFrontmatter } = await entry.render();
|
|||
categories={entry.data.categories}
|
||||
></PostMetadata>
|
||||
|
||||
<div class="border-[var(--line-divider)] border-dashed border-b-[1px] mb-5"></div>
|
||||
<!-- always show cover as long as it has one -->
|
||||
|
||||
{entry.data.cover &&
|
||||
<ImageBox src={entry.data.cover} class="mb-8 rounded-xl"/>
|
||||
}
|
||||
|
||||
{!entry.data.cover && <div class="border-[var(--line-divider)] border-dashed border-b-[1px] mb-5"></div>}
|
||||
|
||||
<div class="prose dark:prose-invert max-w-none prose-h1:text-3xl">
|
||||
<Content />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between gap-4 overflow-hidden w-full">
|
||||
<a href={getPostUrlBySlug(entry.data.prevSlug)} class="w-full font-bold overflow-hidden">
|
||||
{entry.data.prevSlug && <Button class="w-full max-w-full h-10 px-4 rounded-2xl flex items-center justify-start gap-4" card height="60px">
|
||||
<Icon name="material-symbols:chevron-left-rounded" size={32} class="text-[var(--primary)]" />
|
||||
<div class="overflow-hidden overflow-ellipsis whitespace-nowrap max-w-[calc(100%_-_48px)] text-black/75 dark:text-white/75">
|
||||
{entry.data.prevTitle}
|
||||
</div>
|
||||
</Button>}
|
||||
</a>
|
||||
|
||||
<a href={getPostUrlBySlug(entry.data.nextSlug)} class="w-full font-bold overflow-hidden">
|
||||
{entry.data.nextSlug && <Button class="w-full max-w-full h-10 px-4 rounded-2xl flex items-center justify-end gap-4" card height="60px">
|
||||
<div class="overflow-hidden overflow-ellipsis whitespace-nowrap max-w-[calc(100%_-_48px)] text-black/75 dark:text-white/75">
|
||||
{entry.data.nextTitle}
|
||||
</div>
|
||||
<Icon name="material-symbols:chevron-right-rounded" size={32} class="text-[var(--primary)]" />
|
||||
</Button>}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</MainGridLayout>
|
||||
|
|
|
@ -1,12 +1,23 @@
|
|||
import {getCollection} from "astro:content";
|
||||
import {CollectionEntry, getCollection} from "astro:content";
|
||||
|
||||
export async function getSortedPosts() {
|
||||
const allBlogPosts = await getCollection("posts");
|
||||
return allBlogPosts.sort((a, b) => {
|
||||
const sorted = allBlogPosts.sort((a, b) => {
|
||||
const dateA = new Date(a.data.pubDate);
|
||||
const dateB = new Date(b.data.pubDate);
|
||||
return dateA > dateB ? -1 : 1;
|
||||
});
|
||||
|
||||
for (let i = 1; i < sorted.length; i++) {
|
||||
sorted[i].data.nextSlug = sorted[i - 1].slug;
|
||||
sorted[i].data.nextTitle = sorted[i - 1].data.title;
|
||||
}
|
||||
for (let i = 0; i < sorted.length - 1; i++) {
|
||||
sorted[i].data.prevSlug = sorted[i + 1].slug;
|
||||
sorted[i].data.prevTitle = sorted[i + 1].data.title;
|
||||
}
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
export function getPostUrlBySlug(slug: string): string {
|
||||
|
|
|
@ -8,5 +8,9 @@
|
|||
"name": "@astrojs/ts-plugin"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/**",
|
||||
"src/**/**/**",
|
||||
]
|
||||
}
|
|
@ -2,6 +2,7 @@ appearance:
|
|||
hue: 250
|
||||
|
||||
banner:
|
||||
enable: true
|
||||
url: https://saicaca.github.io/vivia-preview/assets/banner.jpg
|
||||
|
||||
profile:
|
||||
|
|
Loading…
Reference in New Issue