feat: back-to-top, footer, about page, responsive design, etc.
(cherry picked from commit 21319d339305c77311d42aa18501d425a5a2619c)
This commit is contained in:
parent
124843848f
commit
8ed0aa071f
|
@ -85,12 +85,12 @@ function formatDate(date: Date) {
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- post title -->
|
<!-- post title -->
|
||||||
<div class="max-w-[65%] w-[65%] transition text-left font-bold">
|
<div class="max-w-[65%] w-[65%] text-left font-bold
|
||||||
<div class="group-hover:ml-1 transition-all group-hover:text-[var(--primary)]
|
group-hover:translate-x-1 transition-all group-hover:text-[var(--primary)]
|
||||||
text-black/80 dark:text-white/80 pr-8 whitespace-nowrap overflow-ellipsis overflow-hidden">
|
text-black/80 dark:text-white/80 pr-8 whitespace-nowrap overflow-ellipsis overflow-hidden"
|
||||||
|
>
|
||||||
{post.data.title}
|
{post.data.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<!-- tag list -->
|
<!-- tag list -->
|
||||||
<div class="w-[15%] text-left text-sm transition
|
<div class="w-[15%] text-left text-sm transition
|
||||||
whitespace-nowrap overflow-ellipsis overflow-hidden
|
whitespace-nowrap overflow-ellipsis overflow-hidden
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="card-base max-w-[var(--page-width)] min-h-[72px] rounded-b-none mx-auto flex items-center px-6">
|
||||||
|
<div class="text-black/50 dark:text-white/50 text-sm">
|
||||||
|
© 2023 Author. All Rights Reserved.
|
||||||
|
<br>
|
||||||
|
Powered by Vivia
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -65,6 +65,8 @@ color_set({
|
||||||
|
|
||||||
--deep-text: oklch(0.25 0.02 var(--hue))
|
--deep-text: oklch(0.25 0.02 var(--hue))
|
||||||
|
|
||||||
|
--line-divider: black(0.08) white(0.08)
|
||||||
|
|
||||||
--line-color: black(0.1) white(0.1)
|
--line-color: black(0.1) white(0.1)
|
||||||
--meta-divider: black(0.2) white(0.2)
|
--meta-divider: black(0.2) white(0.2)
|
||||||
--selection-bg: oklch(0.90 0.05 var(--hue)) oklch(0.40 0.08 var(--hue))
|
--selection-bg: oklch(0.90 0.05 var(--hue)) oklch(0.40 0.08 var(--hue))
|
||||||
|
@ -88,5 +90,8 @@ color_set({
|
||||||
h1, h2, h3, h4, h5, h6, p, a, span, li, ul, ol, blockquote, code, pre, table, th, td, strong {
|
h1, h2, h3, h4, h5, h6, p, a, span, li, ul, ol, blockquote, code, pre, table, th, td, strong {
|
||||||
@apply transition;
|
@apply transition;
|
||||||
}
|
}
|
||||||
|
.card-shadow {
|
||||||
|
@apply drop-shadow-[0_2px_4px_rgba(0,0,0,0.005)]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -15,7 +15,7 @@ const className = Astro.props.class;
|
||||||
<div>
|
<div>
|
||||||
<a href="/"><Button light class="font-bold px-5">Home</Button></a>
|
<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="/archive"><Button light class="font-bold px-5">Archive</Button></a>
|
||||||
<Button light class="font-bold px-5">About</Button>
|
<a href="/about"><Button light class="font-bold px-5">About</Button></a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button id="scheme-switch" iconName="material-symbols:wb-sunny-outline-rounded" iconSize={20} isIcon light></Button>
|
<Button id="scheme-switch" iconName="material-symbols:wb-sunny-outline-rounded" iconSize={20} isIcon light></Button>
|
||||||
|
|
|
@ -30,14 +30,14 @@ const coverWidth = "30%";
|
||||||
const { remarkPluginFrontmatter } = await entry.render();
|
const { remarkPluginFrontmatter } = await entry.render();
|
||||||
|
|
||||||
---
|
---
|
||||||
<div class:list={["card-base flex w-full rounded-[var(--radius-large)] overflow-hidden relative", className]}>
|
<div class:list={["card-base flex flex-col-reverse lg:flex-col w-full rounded-[var(--radius-large)] overflow-hidden relative", className]}>
|
||||||
<div class:list={[" px-10 pt-7 pb-6 relative", {'w-full': !hasCover, "w-[calc(100%_-_var(--coverWidth))]": hasCover}]}>
|
<div class:list={[" px-10 pt-4 lg:pt-7 pb-6 relative", {'w-full': !hasCover, "w-full lg:w-[calc(100%_-_var(--coverWidth))]": hasCover}]}>
|
||||||
<a href={url}
|
<a href={url}
|
||||||
class="transition w-full block font-bold mb-3 text-4xl
|
class="transition w-full block font-bold mb-3 text-4xl
|
||||||
text-black/90 dark:text-white/90
|
text-black/90 dark:text-white/90
|
||||||
hover:text-[var(--primary)] dark:hover:text-[var(--primary)]
|
hover:text-[var(--primary)] dark:hover:text-[var(--primary)]
|
||||||
before:w-1 before:h-5 before:rounded-md before:bg-[var(--primary)]
|
before:w-1 before:h-5 before:rounded-md before:bg-[var(--primary)]
|
||||||
before:absolute before:top-[38px] before:left-5
|
before:absolute before:top-[26px] lg:before:top-[38px] before:left-5
|
||||||
">
|
">
|
||||||
{title}
|
{title}
|
||||||
</a>
|
</a>
|
||||||
|
@ -58,7 +58,10 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasCover && <a href={url}
|
{hasCover && <a href={url}
|
||||||
class=`group w-[var(--coverWidth)] absolute top-3 bottom-3 right-3 rounded-xl overflow-hidden`>
|
class:list={["group",
|
||||||
|
"max-h-[20vh] lg:max-h-none mx-4 mt-4 lg:mx-0 lg:mt-0",
|
||||||
|
"lg:w-[var(--coverWidth)] relative lg:absolute lg:top-3 lg:bottom-3 lg:right-3 rounded-xl overflow-hidden"
|
||||||
|
]} >
|
||||||
<div class="absolute z-10 w-full h-full group-hover:bg-black/30 group-active:bg-black/50 transition"></div>
|
<div class="absolute z-10 w-full h-full group-hover:bg-black/30 group-active:bg-black/50 transition"></div>
|
||||||
<div class="absolute z-20 w-full h-full flex items-center justify-center ">
|
<div class="absolute z-20 w-full h-full flex items-center justify-center ">
|
||||||
<Icon name="material-symbols:chevron-right-rounded"
|
<Icon name="material-symbols:chevron-right-rounded"
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
import { Icon } from 'astro-icon/components';
|
||||||
|
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()">
|
||||||
|
<Button card height="60px" width="60px">
|
||||||
|
<Icon name="material-symbols:keyboard-arrow-up-rounded" class="mx-auto"></Icon>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
.back-to-top-wrapper
|
||||||
|
width: 60px
|
||||||
|
height: 60px
|
||||||
|
position: absolute
|
||||||
|
right: -84px
|
||||||
|
top: 0
|
||||||
|
|
||||||
|
.back-to-top-btn
|
||||||
|
color: var(--primary)
|
||||||
|
font-size: 36px
|
||||||
|
font-weight: bold
|
||||||
|
border: none
|
||||||
|
position: fixed
|
||||||
|
bottom: 240px
|
||||||
|
opacity: 1
|
||||||
|
cursor: pointer
|
||||||
|
i
|
||||||
|
font-size: 28px
|
||||||
|
&.hide
|
||||||
|
transform: scale(0.9)
|
||||||
|
opacity: 0
|
||||||
|
pointer-events: none
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script is:raw>
|
||||||
|
|
||||||
|
function topFunction() {
|
||||||
|
window.scroll({ top: 0, behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
function scrollFunction() {
|
||||||
|
let btn = document.getElementById('back-to-top-btn');
|
||||||
|
if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
|
||||||
|
btn.classList.remove('hide')
|
||||||
|
} else {
|
||||||
|
btn.classList.add('hide')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.onscroll = function() {
|
||||||
|
scrollFunction();
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -45,10 +45,10 @@ import { Icon } from 'astro-icon/components';
|
||||||
'bg-none': light,
|
'bg-none': light,
|
||||||
'hover:bg-[var(--btn-plain-bg-hover)]': light,
|
'hover:bg-[var(--btn-plain-bg-hover)]': light,
|
||||||
'active:bg-[var(--btn-plain-bg-active)]': light,
|
'active:bg-[var(--btn-plain-bg-active)]': light,
|
||||||
'text-neutral-900': light,
|
'text-black/75': light,
|
||||||
'hover:text-[var(--primary)]': light,
|
'hover:text-[var(--primary)]': light,
|
||||||
|
|
||||||
'dark:text-neutral-300': light || regular,
|
'dark:text-white/75': light || regular,
|
||||||
'dark:hover:text-[var(--primary)]': light,
|
'dark:hover:text-[var(--primary)]': light,
|
||||||
|
|
||||||
'bg-[var(--btn-regular-bg)]': regular,
|
'bg-[var(--btn-regular-bg)]': regular,
|
||||||
|
|
|
@ -11,7 +11,7 @@ const vConf = getConfig();
|
||||||
|
|
||||||
---
|
---
|
||||||
<div class="card-base" transition:persist>
|
<div class="card-base" transition:persist>
|
||||||
<ImageBox src={vConf.profile.avatar} class="w-full rounded-2xl mb-3"></ImageBox>
|
<ImageBox src={vConf.profile.avatar} class="w-[240px] mt-4 mx-auto lg:w-full lg:mt-0 rounded-2xl mb-3"></ImageBox>
|
||||||
<div class="font-bold text-lg text-center mb-1 dark:text-neutral-50 transition">{vConf.profile.author}</div>
|
<div class="font-bold text-lg text-center mb-1 dark:text-neutral-50 transition">{vConf.profile.author}</div>
|
||||||
<div class="h-1 w-5 bg-[var(--primary)] mx-auto rounded-full mb-3 transition"></div>
|
<div class="h-1 w-5 bg-[var(--primary)] mx-auto rounded-full mb-3 transition"></div>
|
||||||
<div class="text-center text-neutral-400 mb-2 transition">{vConf.profile.subtitle}</div>
|
<div class="text-center text-neutral-400 mb-2 transition">{vConf.profile.subtitle}</div>
|
||||||
|
|
|
@ -3,6 +3,8 @@ import Layout from "./Layout.astro";
|
||||||
import Navbar from "../components/Navbar.astro";
|
import Navbar from "../components/Navbar.astro";
|
||||||
import SideBar from "../components/widget/SideBar.astro";
|
import SideBar from "../components/widget/SideBar.astro";
|
||||||
import {pathsEqual} from "../utils/url-utils";
|
import {pathsEqual} from "../utils/url-utils";
|
||||||
|
import Footer from "../components/Footer.astro";
|
||||||
|
import BackToTop from "../components/control/BackToTop.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -18,7 +20,7 @@ const sidebarWidth = "280px";
|
||||||
|
|
||||||
---
|
---
|
||||||
<Layout title={title} banner={banner}>
|
<Layout title={title} banner={banner}>
|
||||||
<div class=`max-w-[1200px] grid grid-cols-[280px_auto] grid-auto-rows-[auto] mx-auto gap-4 relative`
|
<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"
|
transition:animate="none"
|
||||||
>
|
>
|
||||||
<div id="top-row" class="col-span-2 grid-rows-1" class:list={{
|
<div id="top-row" class="col-span-2 grid-rows-1" class:list={{
|
||||||
|
@ -27,14 +29,21 @@ const sidebarWidth = "280px";
|
||||||
>
|
>
|
||||||
<Navbar transition:animate="fade" transition:persist></Navbar>
|
<Navbar transition:animate="fade" transition:persist></Navbar>
|
||||||
</div>
|
</div>
|
||||||
<SideBar class="max-w-[280px] col-span-1 grid-rows-2" transition:persist></SideBar>
|
<SideBar class="row-start-3 row-end-4 col-span-2 lg:row-start-2 lg:row-end-3 lg:col-span-1 lg:max-w-[280px] overflow-hidden" transition:persist></SideBar>
|
||||||
|
|
||||||
<div class="grid-rows-2 grid-cols-2 overflow-hidden" transition:animate="slide">
|
<div class="row-start-2 row-end-3 col-span-2 lg:col-span-1 overflow-hidden" transition:animate="slide">
|
||||||
<!-- the overflow-hidden here prevent long text break the layout-->
|
<!-- the overflow-hidden here prevent long text break the layout-->
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid-rows-3 col-span-2 mt-4" transition:persist>
|
||||||
|
<Footer></Footer>
|
||||||
|
</div>
|
||||||
|
<BackToTop></BackToTop>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
import MainGridLayout from "../layouts/MainGridLayout.astro";
|
||||||
|
|
||||||
|
import { getEntry } from 'astro:content'
|
||||||
|
|
||||||
|
const aboutPost = await getEntry('spec', 'about')
|
||||||
|
|
||||||
|
const { Content } = await aboutPost.render()
|
||||||
|
|
||||||
|
---
|
||||||
|
<MainGridLayout>
|
||||||
|
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative min-h-[120px]">
|
||||||
|
<div class="card-base z-10 px-9 py-6 relative w-full ">
|
||||||
|
<div class="prose dark:prose-invert max-w-none prose-h1:text-3xl">
|
||||||
|
<Content />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MainGridLayout>
|
|
@ -30,13 +30,13 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||||
]}>
|
]}>
|
||||||
<div class="flex flex-row text-black/30 dark:text-white/30 gap-5 mb-3 transition">
|
<div class="flex flex-row text-black/30 dark:text-white/30 gap-5 mb-3 transition">
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<div class="transition h-6 w-6 rounded-md bg-black/5 dark:bg-white/5 text-black/50 dark:text-white/50 flex items-center justify-center mr-2">
|
<div class="transition h-6 w-6 rounded-md bg-black/5 dark:bg-white/10 text-black/50 dark:text-white/50 flex items-center justify-center mr-2">
|
||||||
<Icon name="material-symbols:notes-rounded"></Icon>
|
<Icon name="material-symbols:notes-rounded"></Icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm">{remarkPluginFrontmatter.words} words</div>
|
<div class="text-sm">{remarkPluginFrontmatter.words} words</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<div class="transition h-6 w-6 rounded-md bg-black/5 dark:bg-white/5 text-black/50 dark:text-white/50 flex items-center justify-center mr-2">
|
<div class="transition h-6 w-6 rounded-md bg-black/5 dark:bg-white/10 text-black/50 dark:text-white/50 flex items-center justify-center mr-2">
|
||||||
<Icon name="material-symbols:schedule-outline-rounded"></Icon>
|
<Icon name="material-symbols:schedule-outline-rounded"></Icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm">{remarkPluginFrontmatter.minutes} minutes</div>
|
<div class="text-sm">{remarkPluginFrontmatter.minutes} minutes</div>
|
||||||
|
@ -59,7 +59,7 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||||
categories={entry.data.categories}
|
categories={entry.data.categories}
|
||||||
></PostMetadata>
|
></PostMetadata>
|
||||||
|
|
||||||
<div class="border-b-black/8 dark:border-b-white/8 border-dashed border-b-[1px] mb-5"></div>
|
<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">
|
<div class="prose dark:prose-invert max-w-none prose-h1:text-3xl">
|
||||||
<Content />
|
<Content />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
appearance:
|
appearance:
|
||||||
hue: 290
|
hue: 250
|
||||||
|
|
||||||
banner:
|
banner:
|
||||||
url: https://saicaca.github.io/vivia-preview/assets/banner.jpg
|
url: https://saicaca.github.io/vivia-preview/assets/banner.jpg
|
||||||
|
|
Loading…
Reference in New Issue