mirror of
https://github.com/saicaca/fuwari.git
synced 2026-01-11 23:02:53 +01:00
refactor: code cleanup
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
---
|
||||
import {getSortedPosts} from "../utils/content-utils";
|
||||
import {getPostUrlBySlug} from "../utils/url-utils";
|
||||
import {i18n} from "../i18n/translation";
|
||||
import I18nKey from "../i18n/i18nKey";
|
||||
import {UNCATEGORIZED} from "@constants/constants";
|
||||
|
||||
interface Props {
|
||||
keyword: string;
|
||||
tags: string[];
|
||||
@@ -6,13 +12,6 @@ interface Props {
|
||||
}
|
||||
const { keyword, tags, categories} = Astro.props;
|
||||
|
||||
import Button from "./control/Button.astro";
|
||||
import {getSortedPosts} from "../utils/content-utils";
|
||||
import {getPostUrlBySlug} from "../utils/url-utils";
|
||||
import {i18n} from "../i18n/translation";
|
||||
import I18nKey from "../i18n/i18nKey";
|
||||
import {UNCATEGORIZED} from "@constants/constants";
|
||||
|
||||
let posts = await getSortedPosts()
|
||||
|
||||
if (Array.isArray(tags) && tags.length > 0) {
|
||||
@@ -64,48 +63,51 @@ function formatTag(tag: string[]) {
|
||||
<div class="card-base px-8 py-6">
|
||||
{
|
||||
groups.map(group => (
|
||||
<div>
|
||||
<div class="flex flex-row w-full items-center h-[3.75rem]">
|
||||
<div class="w-[15%] md:w-[10%] transition text-2xl font-bold text-right text-black/75 dark:text-white/75">{group.year}</div>
|
||||
<div class="w-[15%] md:w-[10%]">
|
||||
<div class="h-3 w-3 bg-none rounded-full outline outline-[var(--primary)] mx-auto -outline-offset-[2px] z-50 outline-3"></div>
|
||||
</div>
|
||||
<div class="w-[70%] md:w-[80%] transition text-left text-black/50 dark:text-white/50">{group.posts.length} {i18n(I18nKey.postsCount)}</div>
|
||||
<div>
|
||||
<div class="flex flex-row w-full items-center h-[3.75rem]">
|
||||
<div class="w-[15%] md:w-[10%] transition text-2xl font-bold text-right text-75">{group.year}</div>
|
||||
<div class="w-[15%] md:w-[10%]">
|
||||
<div class="h-3 w-3 bg-none rounded-full outline outline-[var(--primary)] mx-auto -outline-offset-[2px] z-50 outline-3"></div>
|
||||
</div>
|
||||
{group.posts.map(post => (
|
||||
<a href={getPostUrlBySlug(post.slug)} aria-label={post.data.title} class="group">
|
||||
<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-[15%] md:w-[10%] transition text-sm text-right text-black/50 dark:text-white/50">{formatDate(post.data.published)}</div>
|
||||
<!-- dot and line -->
|
||||
<div class="w-[15%] md:w-[10%] relative dash-line h-full flex items-center">
|
||||
<div class="transition-all mx-auto w-1 h-1 rounded group-hover:h-5
|
||||
bg-[oklch(0.5_0.05_var(--hue))] group-hover:bg-[var(--primary)]
|
||||
outline outline-4 z-50
|
||||
outline-[var(--card-bg)]
|
||||
group-hover:outline-[var(--btn-plain-bg-hover)]
|
||||
group-active:outline-[var(--btn-plain-bg-active)]
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
<!-- post title -->
|
||||
<div class="w-[70%] md:max-w-[65%] md:w-[65%] text-left font-bold
|
||||
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"
|
||||
>
|
||||
{post.data.title}
|
||||
</div>
|
||||
<!-- tag list -->
|
||||
<div class="hidden md:block md:w-[15%] text-left text-sm transition
|
||||
whitespace-nowrap overflow-ellipsis overflow-hidden
|
||||
text-black/30 dark:text-white/30"
|
||||
>{formatTag(post.data.tags)}</div>
|
||||
</div>
|
||||
</Button>
|
||||
</a>
|
||||
))}
|
||||
<div class="w-[70%] md:w-[80%] transition text-left text-50">{group.posts.length} {i18n(I18nKey.postsCount)}</div>
|
||||
</div>
|
||||
{group.posts.map(post => (
|
||||
<a href={getPostUrlBySlug(post.slug)}
|
||||
aria-label={post.data.title}
|
||||
class="group btn-plain block h-10 w-full rounded-lg hover:text-[initial]"
|
||||
>
|
||||
<div class="flex flex-row justify-start items-center h-full">
|
||||
<!-- date -->
|
||||
<div class="w-[15%] md:w-[10%] transition text-sm text-right text-50">
|
||||
{formatDate(post.data.published)}
|
||||
</div>
|
||||
<!-- dot and line -->
|
||||
<div class="w-[15%] md:w-[10%] relative dash-line h-full flex items-center">
|
||||
<div class="transition-all mx-auto w-1 h-1 rounded group-hover:h-5
|
||||
bg-[oklch(0.5_0.05_var(--hue))] group-hover:bg-[var(--primary)]
|
||||
outline outline-4 z-50
|
||||
outline-[var(--card-bg)]
|
||||
group-hover:outline-[var(--btn-plain-bg-hover)]
|
||||
group-active:outline-[var(--btn-plain-bg-active)]
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
<!-- post title -->
|
||||
<div class="w-[70%] md:max-w-[65%] md:w-[65%] text-left font-bold
|
||||
group-hover:translate-x-1 transition-all group-hover:text-[var(--primary)]
|
||||
text-75 pr-8 whitespace-nowrap overflow-ellipsis overflow-hidden"
|
||||
>
|
||||
{post.data.title}
|
||||
</div>
|
||||
<!-- tag list -->
|
||||
<div class="hidden md:block md:w-[15%] text-left text-sm transition
|
||||
whitespace-nowrap overflow-ellipsis overflow-hidden
|
||||
text-30"
|
||||
>{formatTag(post.data.tags)}</div>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
|
||||
---
|
||||
<div class="rounded-2xl drop-shadow-2xl bg-white">
|
||||
<slot />
|
||||
</div>
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import ButtonLight from "./control/Button.astro";
|
||||
---
|
||||
<ButtonLight class="fill-black">
|
||||
<Icon name="material-symbols:nightlight-badge-outline" class="w-6 h-6"/>
|
||||
</ButtonLight>
|
||||
@@ -1,60 +0,0 @@
|
||||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
body: string;
|
||||
href: string;
|
||||
}
|
||||
const { href, title, body } = Astro.props;
|
||||
---
|
||||
|
||||
<li class="link-card">
|
||||
<a href={href}>
|
||||
<h2>
|
||||
{title}
|
||||
<span class="">→</span>
|
||||
</h2>
|
||||
<p>
|
||||
{body}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<style>
|
||||
.link-card {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
padding: 1px;
|
||||
background-color: #23262d;
|
||||
background-image: none;
|
||||
background-size: 400%;
|
||||
border-radius: 7px;
|
||||
background-position: 100%;
|
||||
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.link-card > a {
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
line-height: 1.4;
|
||||
padding: calc(1.5rem - 1px);
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
background-color: #23262d;
|
||||
opacity: 0.8;
|
||||
}
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
p {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.link-card:is(:hover, :focus-within) {
|
||||
background-position: 0;
|
||||
background-image: var(--accent-gradient);
|
||||
}
|
||||
.link-card:is(:hover, :focus-within) h2 {
|
||||
color: rgb(var(--accent-light));
|
||||
}
|
||||
</style>
|
||||
@@ -5,7 +5,7 @@ import {profileConfig} from "../config";
|
||||
---
|
||||
|
||||
<div class="card-base max-w-[var(--page-width)] min-h-[4.5rem] rounded-b-none mx-auto flex items-center px-6">
|
||||
<div class="text-black/50 dark:text-white/50 text-sm">
|
||||
<div class="text-50 text-sm">
|
||||
© 2023 {profileConfig.name}. All Rights Reserved.
|
||||
<br>
|
||||
Powered by <a class="link text-[var(--primary)]" target="_blank" href="https://github.com/saicaca/fuwari">Fuwari</a>
|
||||
|
||||
@@ -199,11 +199,36 @@ color_set({
|
||||
@apply bg-transparent text-[var(--primary)]
|
||||
}
|
||||
|
||||
.text-deep {
|
||||
.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 flex items-center justify-center bg-none hover:bg-[var(--btn-plain-bg-hover)] active:bg-[var(--btn-plain-bg-active)]
|
||||
text-black/75 hover:text-[var(--primary)] dark:text-white/75 dark: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
|
||||
}
|
||||
|
||||
.text-90 {
|
||||
@apply text-black/90 dark:text-white/90
|
||||
}
|
||||
.text-sub {
|
||||
.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
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,85 +1,65 @@
|
||||
---
|
||||
import Button from "./control/Button.astro";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import DisplaySetting from "./widget/DisplaySetting.astro";
|
||||
import I18nKey from "../i18n/i18nKey";
|
||||
import {i18n} from "../i18n/translation";
|
||||
import DisplaySettings from "./widget/DisplaySettings.svelte";
|
||||
import {LinkPreset, NavBarLink} from "../types/config";
|
||||
import {navBarConfig, siteConfig} from "../config";
|
||||
import NavMenuPanel from "./widget/NavMenuPanel.astro";
|
||||
import SearchPanel from "./SearchPanel.vue"
|
||||
import Search from "./Search.svelte";
|
||||
import {LinkPresets} from "../constants/link-presets";
|
||||
const className = Astro.props.class;
|
||||
|
||||
function isI18nKey(key: string): key is I18nKey {
|
||||
return Object.values(I18nKey).includes(key);
|
||||
}
|
||||
|
||||
let links: NavBarLink[] = navBarConfig.links.map((item) => {
|
||||
let links: NavBarLink[] = navBarConfig.links.map((item: NavBarLink | LinkPreset): NavBarLink => {
|
||||
if (typeof item === "number") {
|
||||
return getLinkPresetInfo(item)
|
||||
return LinkPresets[item]
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
function getLinkPresetInfo(p: LinkPreset): NavBarLink {
|
||||
switch (p) {
|
||||
case LinkPreset.Home:
|
||||
return {
|
||||
name: i18n(I18nKey.home),
|
||||
url: "/page/1"
|
||||
};
|
||||
case LinkPreset.Archive:
|
||||
return {
|
||||
name: i18n(I18nKey.archive),
|
||||
url: "/archive"
|
||||
};
|
||||
case LinkPreset.About:
|
||||
return {
|
||||
name: i18n(I18nKey.about),
|
||||
url: "/about"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
<div transition:animate="none" class:list={[
|
||||
className,
|
||||
"card-base sticky top-0 overflow-visible max-w-[var(--page-width)] h-[4.5rem] rounded-t-none mx-auto flex items-center justify-between px-4"]}>
|
||||
<a href="/page/1"><Button height="3.25rem" class="px-5 font-bold rounded-lg active:scale-95" light>
|
||||
<a href="/page/1" class="btn-plain h-[3.25rem] px-5 font-bold rounded-lg active:scale-95">
|
||||
<div class="flex flex-row text-[var(--primary)] items-center text-md">
|
||||
<Icon name="material-symbols:home-outline-rounded" size={"1.75rem"} class="mb-1 mr-2" />
|
||||
{siteConfig.title}
|
||||
</div>
|
||||
</Button></a>
|
||||
<div class="hidden md:block">
|
||||
</a>
|
||||
<div class="hidden md:flex">
|
||||
{links.map((l) => {
|
||||
return <a aria-label={l.name} href={l.url} target={l.external ? "_blank" : null}>
|
||||
<Button light class="font-bold px-5 rounded-lg active:scale-95">
|
||||
<div class="flex items-center">
|
||||
{l.name}
|
||||
{l.external && <Icon size="14" name="fa6-solid:arrow-up-right-from-square" class="transition -translate-y-[1px] ml-1 text-black/[0.2] dark:text-white/[0.2]"></Icon>}
|
||||
</div>
|
||||
</Button>
|
||||
return <a aria-label={l.name} href={l.url} target={l.external ? "_blank" : null}
|
||||
class="btn-plain h-11 font-bold px-5 rounded-lg active:scale-95"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
{l.name}
|
||||
{l.external && <Icon size="14" name="fa6-solid:arrow-up-right-from-square" class="transition -translate-y-[1px] ml-1 text-black/[0.2] dark:text-white/[0.2]"></Icon>}
|
||||
</div>
|
||||
</a>;
|
||||
})}
|
||||
</div>
|
||||
<div class="flex">
|
||||
<SearchPanel client:load>
|
||||
<Icon slot="search-icon" name="material-symbols:search" size={"1.25rem"} class="ml-3 transition my-auto text-black/30 dark:text-white/30"></Icon>
|
||||
<!--<SearchPanel client:load>-->
|
||||
<Search client:load>
|
||||
<Icon slot="search-icon" name="material-symbols:search" size={"1.25rem"} class="absolute pointer-events-none ml-3 transition my-auto text-black/30 dark:text-white/30"></Icon>
|
||||
<!--<Icon slot="arrow-icon" name="material-symbols:chevron-right-rounded" size={"1.25rem"} class="transition my-auto text-[var(--primary)]"></Icon>-->
|
||||
<Icon slot="arrow-icon" name="fa6-solid:chevron-right" size={"0.75rem"} class="transition translate-x-0.5 my-auto text-[var(--primary)]"></Icon>
|
||||
<Button slot="search-switch" name="Search Panel" class="block lg:hidden rounded-lg active:scale-90" id="search-switch" iconName="material-symbols:search" iconSize={"1.25rem"} isIcon light></Button>
|
||||
</SearchPanel>
|
||||
<Button name="Display Settings" class="rounded-lg active:scale-90" id="display-settings-switch" iconName="material-symbols:palette-outline" iconSize={"1.25rem"} isIcon light></Button>
|
||||
<Button name="Light/Dark Mode" class="rounded-lg flex items-center justify-center active:scale-90" id="scheme-switch" light height="2.75rem" width="2.75rem">
|
||||
<Icon slot="search-switch" name="material-symbols:search" size={"1.25rem"}></Icon>
|
||||
</Search>
|
||||
<button aria-label="Display Settings" class="btn-plain h-11 w-11 rounded-lg active:scale-90" id="display-settings-switch">
|
||||
<Icon name="material-symbols:palette-outline" size={"1.25rem"}></Icon>
|
||||
</button>
|
||||
<button aria-label="Light/Dark Mode" class="btn-plain h-11 w-11 rounded-lg active:scale-90" id="scheme-switch">
|
||||
<Icon name="material-symbols:wb-sunny-outline-rounded" size={"1.25rem"} class="absolute opacity-[var(--display-light-icon)]"></Icon>
|
||||
<Icon name="material-symbols:dark-mode-outline-rounded" size={"1.25rem"} class="absolute opacity-[var(--display-dark-icon)]"></Icon>
|
||||
</Button>
|
||||
<Button name="Nav Menu" class="rounded-lg active:scale-90 block md:hidden" id="nav-menu-switch" iconName="material-symbols:menu-rounded" iconSize={"1.25rem"} isIcon light></Button>
|
||||
</button>
|
||||
<button name="Nav Menu" class="btn-plain w-11 h-11 rounded-lg active:scale-90 md:hidden" id="nav-menu-switch">
|
||||
<Icon name="material-symbols:menu-rounded" size={"1.25rem"}></Icon>
|
||||
</button>
|
||||
</div>
|
||||
<DisplaySetting></DisplaySetting>
|
||||
<NavMenuPanel links={links}></NavMenuPanel>
|
||||
|
||||
<DisplaySettings client:only="svelte">
|
||||
<Icon slot="restore-icon" name="fa6-solid:arrow-rotate-left" size={"0.875rem"} class=""></Icon>
|
||||
</DisplaySettings>
|
||||
</div>
|
||||
|
||||
<style lang="stylus">
|
||||
@@ -125,12 +105,13 @@ document.addEventListener('astro:after-swap', () => {
|
||||
|
||||
{import.meta.env.PROD && <script is:raw>
|
||||
async function loadPagefind() {
|
||||
const pagefind = await import("/pagefind/pagefind.js")
|
||||
const pagefind = await import('/pagefind/pagefind.js')
|
||||
await pagefind.options({
|
||||
"excerptLength": 20
|
||||
'excerptLength': 20
|
||||
})
|
||||
pagefind.init()
|
||||
window.pagefind = pagefind
|
||||
pagefind.search('') // speed up the first search
|
||||
}
|
||||
loadPagefind()
|
||||
</script>}
|
||||
@@ -1,6 +1,12 @@
|
||||
---
|
||||
import path from "path";
|
||||
import PostMetadata from "./PostMetadata.astro";
|
||||
import PostMetadata from "./PostMeta.astro";
|
||||
import ImageWrapper from "./misc/ImageWrapper.astro";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import {i18n} from "../i18n/translation";
|
||||
import I18nKey from "../i18n/i18nKey";
|
||||
import {getDir} from "../utils/url-utils";
|
||||
|
||||
interface Props {
|
||||
class: string;
|
||||
entry: any;
|
||||
@@ -16,14 +22,6 @@ interface Props {
|
||||
}
|
||||
const { entry, title, url, published, tags, category, image, description, words } = Astro.props;
|
||||
const className = Astro.props.class;
|
||||
// console.log(Astro.props);
|
||||
import ImageBox from "./misc/ImageBox.astro";
|
||||
import ButtonTag from "./control/ButtonTag.astro";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import Button from "./control/Button.astro";
|
||||
import {i18n} from "../i18n/translation";
|
||||
import I18nKey from "../i18n/i18nKey";
|
||||
import {getDir} from "../utils/url-utils";
|
||||
|
||||
const hasCover = image !== undefined && image !== null && image !== '';
|
||||
|
||||
@@ -35,8 +33,7 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||
<div class:list={["card-base flex flex-col-reverse md:flex-col w-full rounded-[var(--radius-large)] overflow-hidden relative", className]}>
|
||||
<div class:list={["pl-6 md:pl-9 pr-6 md:pr-2 pt-6 md:pt-7 pb-6 relative", {"w-full md:w-[calc(100%_-_52px_-_12px)]": !hasCover, "w-full md:w-[calc(100%_-_var(--coverWidth)_-_12px)]": hasCover}]}>
|
||||
<a href={url}
|
||||
class="transition w-full block font-bold mb-3 text-3xl
|
||||
text-black/90 dark:text-white/90
|
||||
class="transition w-full block font-bold mb-3 text-3xl text-90
|
||||
hover:text-[var(--primary)] dark:hover:text-[var(--primary)]
|
||||
active:text-[var(--title-active)] dark:active:text-[var(--title-active)]
|
||||
before:w-1 before:h-5 before:rounded-md before:bg-[var(--primary)]
|
||||
@@ -48,10 +45,12 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||
<!-- metadata -->
|
||||
<PostMetadata published={published} tags={tags} category={category} hideTagsForMobile={true} class:list={{"mb-4": description, "mb-6": !description}}></PostMetadata>
|
||||
|
||||
<div class="transition text-black/75 dark:text-white/75 mb-3.5">
|
||||
<!-- description -->
|
||||
<div class="transition text-75 mb-3.5">
|
||||
{ description }
|
||||
</div>
|
||||
|
||||
<!-- word count and read time -->
|
||||
<div class="text-sm text-black/30 dark:text-white/30 flex gap-4 transition">
|
||||
<div>{remarkPluginFrontmatter.words} {" " + i18n(I18nKey.wordsCount)}</div>
|
||||
<div>|</div>
|
||||
@@ -71,26 +70,23 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||
class="transition opacity-0 group-hover:opacity-100 text-white text-5xl">
|
||||
</Icon>
|
||||
</div>
|
||||
<ImageBox src={image} basePath={path.join("content/posts/", getDir(entry.id))} alt="Cover Image of the Post"
|
||||
<ImageWrapper src={image} basePath={path.join("content/posts/", getDir(entry.id))} alt="Cover Image of the Post"
|
||||
class="w-full h-full">
|
||||
</ImageBox>
|
||||
</ImageWrapper>
|
||||
</a>}
|
||||
|
||||
{!hasCover &&
|
||||
<a href={url} aria-label={title} class="hidden md:block">
|
||||
<Button name="Enter the Post" width="3.25rem" height="full" class="absolute right-3 top-3 bottom-3 rounded-xl bg-[var(--enter-btn-bg)] hover:bg-[var(--enter-btn-bg-hover)] active:bg-[var(--enter-btn-bg-active)] active:scale-95">
|
||||
<Icon name="material-symbols:chevron-right-rounded"
|
||||
class="transition text-[var(--primary)] text-4xl mx-auto">
|
||||
</Icon>
|
||||
</Button>
|
||||
<a href={url} aria-label={title} class="hidden md:flex btn-regular w-[3.25rem]
|
||||
absolute right-3 top-3 bottom-3 rounded-xl bg-[var(--enter-btn-bg)]
|
||||
hover:bg-[var(--enter-btn-bg-hover)] active:bg-[var(--enter-btn-bg-active)] active:scale-95
|
||||
">
|
||||
<Icon name="material-symbols:chevron-right-rounded"
|
||||
class="transition text-[var(--primary)] text-4xl mx-auto">
|
||||
</Icon>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
<div class="transition border-t-[1px] border-dashed mx-6 border-black/10 dark:border-white/[0.15] last:border-t-0 md:hidden"></div>
|
||||
|
||||
<style lang="stylus" define:vars={{coverWidth}}>
|
||||
:root
|
||||
--btn-enter-bg oklch(0.98 0.005 var(--hue))
|
||||
--btn-enter-bg-dark oklch(0.2 0.02 var(--hue))
|
||||
|
||||
</style>
|
||||
@@ -22,7 +22,7 @@ const className = Astro.props.class;
|
||||
>
|
||||
<Icon name="material-symbols:calendar-today-outline-rounded" class="text-xl"></Icon>
|
||||
</div>
|
||||
<span class="text-black/50 dark:text-white/50 text-sm font-medium">{formatDateToYYYYMMDD(published)}</span>
|
||||
<span class="text-50 text-sm font-medium">{formatDateToYYYYMMDD(published)}</span>
|
||||
</div>
|
||||
|
||||
<!-- categories -->
|
||||
@@ -33,7 +33,7 @@ const className = Astro.props.class;
|
||||
</div>
|
||||
<div class="flex flex-row flex-nowrap">
|
||||
<div><a href=`/archive/category/${category || 'uncategorized'}` aria-label=`View all posts in the ${category} category`
|
||||
class="link-lg transition text-black/50 dark:text-white/50 text-sm font-medium
|
||||
class="link-lg transition text-50 text-sm font-medium
|
||||
hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
|
||||
{category || i18n(I18nKey.uncategorized)}
|
||||
</a></div>
|
||||
@@ -51,12 +51,12 @@ const className = Astro.props.class;
|
||||
class="with-divider"
|
||||
>
|
||||
<a href=`/archive/tag/${tag}` aria-label=`View all posts with the ${tag} tag`
|
||||
class="link-lg transition text-black/50 dark:text-white/50 text-sm font-medium
|
||||
class="link-lg transition text-50 text-sm font-medium
|
||||
hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
|
||||
{tag}
|
||||
</a>
|
||||
</div>)}
|
||||
{!(tags && tags.length > 0) && <div class="transition text-black/50 dark:text-white/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>
|
||||
@@ -70,7 +70,7 @@ const className = Astro.props.class;
|
||||
text-[var(--btn-content)] mr-2
|
||||
}
|
||||
.with-divider {
|
||||
@apply before:content-['/'] before:ml-1.5 before:mr-0.5 before:text-[var(--meta-divider)] before:text-sm
|
||||
@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
|
||||
}
|
||||
}
|
||||
23
src/components/PostPage.astro
Normal file
23
src/components/PostPage.astro
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
import {getPostUrlBySlug} from "@utils/url-utils";
|
||||
import PostCard from "./PostCard.astro";
|
||||
|
||||
const {page} = Astro.props;
|
||||
---
|
||||
<div class="transition flex flex-col rounded-[var(--radius-large)] bg-[var(--card-bg)] py-1 md:py-0 md:bg-transparent md:gap-4 mb-4">
|
||||
{page.data.map((entry: { data: { draft: boolean; title: string; tags: string[]; category: string; published: Date; image: string; description: string; }; slug: string; }) => {
|
||||
return (
|
||||
<PostCard
|
||||
entry={entry}
|
||||
title={entry.data.title}
|
||||
tags={entry.data.tags}
|
||||
category={entry.data.category}
|
||||
published={entry.data.published}
|
||||
url={getPostUrlBySlug(entry.slug)}
|
||||
image={entry.data.image}
|
||||
description={entry.data.description}
|
||||
draft={entry.data.draft}
|
||||
></PostCard>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
import {formatDateToYYYYMMDD} from "../utils/date-utils";
|
||||
interface Props {
|
||||
title: string;
|
||||
url: string;
|
||||
published: Date;
|
||||
tags: string[];
|
||||
image: string;
|
||||
description: string;
|
||||
words: number;
|
||||
}
|
||||
const { title, url, published, tags, image, description, words } = Astro.props;
|
||||
// console.log(Astro.props);
|
||||
import ImageBox from "./misc/ImageBox.astro";
|
||||
import ButtonTag from "./control/ButtonTag.astro";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
// tags = ['Foo', 'Bar', 'Baz', 'Qux', 'Quux'];
|
||||
|
||||
// const cover = 'https://saicaca.github.io/vivia-preview/assets/79905307_p0.jpg';
|
||||
// cover = null;
|
||||
const hasCover = image !== undefined && image !== null && image !== '';
|
||||
|
||||
|
||||
---
|
||||
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative">
|
||||
<div class:list={["card-base z-30 px-8 py-6 relative ",
|
||||
{
|
||||
'w-[calc(70%_+_var(--radius-large))]': hasCover,
|
||||
'w-[calc(100%_-_76px_+_var(--radius-large))]': !hasCover,
|
||||
}
|
||||
]}>
|
||||
<a href={url}
|
||||
class="transition w-full block font-bold mb-1 text-3xl
|
||||
text-neutral-900 dark:text-neutral-100
|
||||
hover:text-[var(--primary)] dark:hover:text-[var(--primary)]
|
||||
before:w-1 before:h-4 before:rounded-md before:bg-[var(--primary)]
|
||||
before:absolute before:top-8 before:left-4
|
||||
">
|
||||
This is a very long title
|
||||
</a>
|
||||
<div class="flex text-neutral-500 dark:text-neutral-400 items-center mb-1">
|
||||
<div>{formatDateToYYYYMMDD(published)}</div>
|
||||
<div class="transition h-1 w-1 rounded-sm bg-neutral-400 dark:bg-neutral-600 mx-3"></div>
|
||||
<div>Uncategorized</div>
|
||||
<div class="transition h-1 w-1 rounded-sm bg-neutral-400 dark:bg-neutral-600 mx-3"></div>
|
||||
<div>{words} words</div>
|
||||
</div>
|
||||
<div class="flex gap-2 mb-4">
|
||||
{tags.map(t => (
|
||||
<ButtonTag dot>{t}</ButtonTag>
|
||||
))}
|
||||
</div>
|
||||
<div class="transition text-neutral-700 dark:text-neutral-300">This is the description of the article</div>
|
||||
|
||||
</div>
|
||||
{!hasCover && <a href={url}
|
||||
class="transition w-[72px]
|
||||
bg-[var(--btn-enter-bg)] dark:bg-[var(--btn-enter-bg-dark)]
|
||||
hover:bg-[var(--btn-card-bg-hover)] active:bg-[var(--btn-card-bg-active)]
|
||||
absolute top-0 bottom-0 right-0 flex items-center">
|
||||
<Icon name="material-symbols:chevron-right-rounded"
|
||||
class="transition text-4xl text-[var(--primary)] ml-[22px]"></Icon>
|
||||
</a>}
|
||||
|
||||
{hasCover && <a href={url}
|
||||
class="group w-[30%] absolute top-0 bottom-0 right-0">
|
||||
<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 ">
|
||||
<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"
|
||||
class="w-full h-full">
|
||||
</ImageBox>
|
||||
</a>}
|
||||
</div>
|
||||
|
||||
<style lang="stylus">
|
||||
:root
|
||||
--btn-enter-bg oklch(0.98 0.005 var(--hue))
|
||||
--btn-enter-bg-dark oklch(0.2 0.02 var(--hue))
|
||||
</style>
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
interface Props {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const {name} = Astro.props;
|
||||
|
||||
import BasicCard from "./BasicCard.astro";
|
||||
|
||||
---
|
||||
|
||||
<BasicCard >
|
||||
<div class="p-4">
|
||||
<div>{name}</div>
|
||||
</div>
|
||||
</BasicCard>
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
<div class="card-base w-full h-[200px]">
|
||||
|
||||
</div>
|
||||
@@ -1,51 +1,50 @@
|
||||
---
|
||||
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 hidden lg:block" transition:persist>
|
||||
<div id="back-to-top-btn" class="back-to-top-btn hide flex items-center rounded-2xl overflow-hidden transition" onclick="topFunction()">
|
||||
<Button name="Back to Top" card height="60px" width="60px">
|
||||
<div id="back-to-top-btn" class="back-to-top-btn hide flex items-center rounded-2xl overflow-hidden transition" onclick="backToTop()">
|
||||
<button aria-label="Back to Top" class="btn-card h-[3.75rem] w-[3.75rem]">
|
||||
<Icon name="material-symbols:keyboard-arrow-up-rounded" class="mx-auto"></Icon>
|
||||
</Button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="stylus">
|
||||
.back-to-top-wrapper
|
||||
width: 60px
|
||||
height: 60px
|
||||
width: 3.75rem
|
||||
height: 3.75rem
|
||||
position: absolute
|
||||
right: 0
|
||||
top: 0
|
||||
|
||||
.back-to-top-btn
|
||||
color: var(--primary)
|
||||
font-size: 36px
|
||||
font-size: 2.25rem
|
||||
font-weight: bold
|
||||
border: none
|
||||
position: fixed
|
||||
bottom: 240px
|
||||
bottom: 15rem
|
||||
opacity: 1
|
||||
cursor: pointer
|
||||
transform: translateX(80px)
|
||||
transform: translateX(5rem)
|
||||
i
|
||||
font-size: 28px
|
||||
font-size: 1.75rem
|
||||
&.hide
|
||||
transform: translateX(80px) scale(0.9)
|
||||
transform: translateX(5rem) scale(0.9)
|
||||
opacity: 0
|
||||
pointer-events: none
|
||||
&:active
|
||||
transform: translateX(80px) scale(0.9)
|
||||
transform: translateX(5rem) scale(0.9)
|
||||
|
||||
</style>
|
||||
|
||||
<script is:raw>
|
||||
|
||||
function topFunction() {
|
||||
function backToTop() {
|
||||
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) {
|
||||
@@ -54,7 +53,5 @@ function scrollFunction() {
|
||||
btn.classList.add('hide')
|
||||
}
|
||||
}
|
||||
window.onscroll = function() {
|
||||
scrollFunction();
|
||||
}
|
||||
window.onscroll = scrollFunction
|
||||
</script>
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
---
|
||||
interface Props {
|
||||
id?: string;
|
||||
name?: string;
|
||||
isIcon?: boolean;
|
||||
iconName?: string;
|
||||
width?: string;
|
||||
height?: string;
|
||||
regular?: boolean;
|
||||
light?: boolean
|
||||
card?: boolean;
|
||||
iconSize?: number,
|
||||
class?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
const props = Astro.props;
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
isIcon = false,
|
||||
iconName,
|
||||
width,
|
||||
height = '2.75rem',
|
||||
regular,
|
||||
light,
|
||||
iconSize = 24,
|
||||
card,
|
||||
disabled = false,
|
||||
} = Astro.props;
|
||||
const className = Astro.props.class;
|
||||
import { Icon } from 'astro-icon/components';
|
||||
---
|
||||
|
||||
<button id={id}
|
||||
disabled={disabled}
|
||||
aria-label={name}
|
||||
class:list={[
|
||||
className,
|
||||
`
|
||||
transition
|
||||
h-[var(--height)]
|
||||
`,
|
||||
{
|
||||
'w-[var(--width)]': width,
|
||||
'w-[var(--height)]': isIcon,
|
||||
|
||||
'bg-none': light,
|
||||
'hover:bg-[var(--btn-plain-bg-hover)]': light,
|
||||
'active:bg-[var(--btn-plain-bg-active)]': light,
|
||||
'text-black/75': light,
|
||||
'hover:text-[var(--primary)]': light,
|
||||
|
||||
'dark:text-white/75': light || regular,
|
||||
'dark:hover:text-[var(--primary)]': light,
|
||||
|
||||
'bg-[var(--btn-regular-bg)]': regular,
|
||||
'hover:bg-[var(--btn-regular-bg-hover)]': regular,
|
||||
'active:bg-[var(--btn-regular-bg-active)]': regular,
|
||||
'text-[var(--btn-content)]': regular,
|
||||
|
||||
|
||||
'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,
|
||||
'disabled:dark:text-white/10': card,
|
||||
}
|
||||
]}
|
||||
>
|
||||
{props.isIcon && <Icon class="mx-auto" name={props.iconName} size={iconSize}></Icon> }
|
||||
<slot />
|
||||
</button>
|
||||
|
||||
<style define:vars={{ height, width, iconSize }}>
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,4 @@
|
||||
---
|
||||
import Button from "./Button.astro";
|
||||
interface Props {
|
||||
size?: string;
|
||||
dot?: boolean;
|
||||
@@ -8,9 +7,7 @@ interface Props {
|
||||
}
|
||||
const { size, dot, href, label }: Props = Astro.props;
|
||||
---
|
||||
<a href={href} aria-label={label}>
|
||||
<Button regular height="2rem" class="text-sm 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>
|
||||
<a href={href} aria-label={label} class="btn-regular h-8 text-sm px-3 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>
|
||||
</a>
|
||||
|
||||
@@ -11,7 +11,6 @@ const {page} = Astro.props;
|
||||
const HIDDEN = -1;
|
||||
|
||||
const className = Astro.props.class;
|
||||
import Button from "./Button.astro";
|
||||
|
||||
const ADJ_DIST = 2;
|
||||
const VISIBLE = ADJ_DIST * 2 + 1;
|
||||
@@ -51,13 +50,22 @@ if (r < page.lastPage)
|
||||
|
||||
const parts: string[] = page.url.current.split('/');
|
||||
const commonUrl: string = parts.slice(0, -1).join('/') + '/';
|
||||
|
||||
const getPageUrl = (p: number) => {
|
||||
if (p == 1)
|
||||
return commonUrl;
|
||||
return commonUrl + p;
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
<div class:list={[className, "flex flex-row gap-3 justify-center"]}>
|
||||
<a href={page.url.prev} aria-label={page.url.prev ? "Previous Page" : null}>
|
||||
<Button isIcon card iconName="material-symbols:chevron-left-rounded" class:list={["text-[var(--primary)] rounded-lg", {"active:scale-90": page.url.prev != undefined}]} iconSize={28}
|
||||
disabled = {page.url.prev == undefined}
|
||||
></Button>
|
||||
<a href={page.url.prev} aria-label={page.url.prev ? "Previous Page" : null}
|
||||
class:list={["btn-card overflow-hidden rounded-lg text-[var(--primary)] w-11 h-11",
|
||||
{"disabled": page.url.prev == undefined}
|
||||
]}
|
||||
>
|
||||
<Icon name="material-symbols:chevron-left-rounded" size="1.75rem"></Icon>
|
||||
</a>
|
||||
<div class="bg-[var(--card-bg)] flex flex-row rounded-lg items-center text-neutral-700 dark:text-neutral-300 font-bold">
|
||||
{pages.map((p) => {
|
||||
@@ -69,16 +77,16 @@ const commonUrl: string = parts.slice(0, -1).join('/') + '/';
|
||||
>
|
||||
{p}
|
||||
</div>
|
||||
return <a href={commonUrl + p} aria-label=`Page ${p}`>
|
||||
<Button card iconName="material-symbols:chevron-left-rounded" class="rounded-lg active:scale-[0.85]" height="2.75rem" width="2.75rem">
|
||||
{p}
|
||||
</Button>
|
||||
</a>
|
||||
return <a href={getPageUrl(p)} aria-label=`Page ${p}`
|
||||
class="btn-card w-11 h-11 rounded-lg overflow-hidden active:scale-[0.85]"
|
||||
>{p}</a>
|
||||
})}
|
||||
</div>
|
||||
<a href={page.url.next} aria-label={page.url.next ? "Next Page" : null}>
|
||||
<Button isIcon card name="Next Page" iconName="material-symbols:chevron-right-rounded" class:list={["text-[var(--primary)] rounded-lg", {"active:scale-90": page.url.next != undefined}]} iconSize={28}
|
||||
disabled = {page.url.next == undefined}
|
||||
></Button>
|
||||
<a href={page.url.next} aria-label={page.url.next ? "Next Page" : null}
|
||||
class:list={["btn-card overflow-hidden rounded-lg text-[var(--primary)] w-11 h-11",
|
||||
{"disabled": page.url.next == undefined}
|
||||
]}
|
||||
>
|
||||
<Icon name="material-symbols:chevron-right-rounded" size="1.75rem"></Icon>
|
||||
</a>
|
||||
</div>
|
||||
@@ -1,5 +1,10 @@
|
||||
---
|
||||
import {formatDateToYYYYMMDD} from "../../utils/date-utils";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import {licenseConfig, profileConfig} from "../../config";
|
||||
import {i18n} from "../../i18n/translation";
|
||||
import I18nKey from "../../i18n/i18nKey";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
slug: string;
|
||||
@@ -9,15 +14,8 @@ interface Props {
|
||||
|
||||
const { title, slug, pubDate } = Astro.props;
|
||||
const className = Astro.props.class;
|
||||
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import {licenseConfig, profileConfig} from "../../config";
|
||||
import {i18n} from "../../i18n/translation";
|
||||
import I18nKey from "../../i18n/i18nKey";
|
||||
|
||||
const profileConf = profileConfig;
|
||||
const licenseConf = licenseConfig;
|
||||
|
||||
const postUrl = decodeURIComponent(Astro.url.toString());
|
||||
|
||||
---
|
||||
|
||||
@@ -22,6 +22,12 @@ interface Props {
|
||||
|
||||
<WidgetLayout name={i18n(I18nKey.categories)} id="categories" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT}>
|
||||
{categories.map((c) =>
|
||||
<ButtonLink url={getCategoryUrl(c.name)} badge={c.count} label=`View all posts in the ${c.name} category`>{c.name}</ButtonLink>
|
||||
<ButtonLink
|
||||
url={getCategoryUrl(c.name)}
|
||||
badge={c.count}
|
||||
label=`View all posts in the ${c.name} category`
|
||||
>
|
||||
{c.name}
|
||||
</ButtonLink>
|
||||
)}
|
||||
</WidgetLayout>
|
||||
@@ -8,9 +8,6 @@ interface Props {
|
||||
}
|
||||
|
||||
const links = Astro.props.links;
|
||||
|
||||
const enableBanner = siteConfig.banner.enable;
|
||||
|
||||
---
|
||||
<div id="nav-menu-panel" class:list={["float-panel closed absolute transition-all fixed right-4 px-2 py-2"]}>
|
||||
{links.map((link) => (
|
||||
|
||||
@@ -1,32 +1,29 @@
|
||||
---
|
||||
import ImageBox from "../misc/ImageBox.astro";
|
||||
import Button from "../control/Button.astro";
|
||||
import ImageWrapper from "../misc/ImageWrapper.astro";
|
||||
import {Icon} from "astro-icon/components";
|
||||
import {profileConfig} from "../../config";
|
||||
interface props {
|
||||
|
||||
}
|
||||
const className = Astro.props
|
||||
|
||||
const config = profileConfig;
|
||||
|
||||
---
|
||||
<div class="card-base">
|
||||
<a aria-label="Go to About Page" href="/about" class="group block relative mx-auto mt-4 lg:mx-3 lg:mt-3 mb-3 max-w-[240px] lg:max-w-none overflow-hidden rounded-xl active:scale-95">
|
||||
<div class="absolute transition pointer-events-none group-hover:bg-black/30 group-active:bg-black/50 w-full h-full z-50 flex items-center justify-center">
|
||||
<a aria-label="Go to About Page" href="/about"
|
||||
class="group block relative mx-auto mt-4 lg:mx-3 lg:mt-3 mb-3
|
||||
max-w-[240px] lg:max-w-none overflow-hidden rounded-xl active:scale-95">
|
||||
<div class="absolute transition pointer-events-none group-hover:bg-black/30 group-active:bg-black/50
|
||||
w-full h-full z-50 flex items-center justify-center">
|
||||
<Icon name="fa6-regular:address-card"
|
||||
class="transition opacity-0 group-hover:opacity-100 text-white text-5xl">
|
||||
</Icon>
|
||||
</div>
|
||||
<ImageBox src={config.avatar} alt="Profile Image of the Author" class="mx-auto lg:w-full h-full lg:mt-0 "></ImageBox>
|
||||
<ImageWrapper src={config.avatar} alt="Profile Image of the Author" class="mx-auto lg:w-full h-full lg:mt-0 "></ImageWrapper>
|
||||
</a>
|
||||
<div class="font-bold text-xl text-center mb-1 dark:text-neutral-50 transition">{config.name}</div>
|
||||
<div class="h-1 w-5 bg-[var(--primary)] mx-auto rounded-full mb-2 transition"></div>
|
||||
<div class="text-center text-neutral-400 mb-2.5 transition">{config.bio}</div>
|
||||
<div class="flex gap-2 mx-2 justify-center mb-4">
|
||||
{config.links.map(item =>
|
||||
<a aria-label={item.name} href={item.url} target="_blank">
|
||||
<Button isIcon iconName={item.icon} regular height="40px" class="rounded-lg active:scale-90"></Button>
|
||||
<a aria-label={item.name} href={item.url} target="_blank" class="btn-regular rounded-lg h-10 w-10 active:scale-90">
|
||||
<Icon name={item.icon} size="1.5rem"></Icon>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
import WidgetLayout from "./WidgetLayout.astro";
|
||||
import ButtonLink from "../control/ButtonLink.astro";
|
||||
import {getSortedPosts} from "../../utils/content-utils";
|
||||
import {i18n} from "../../i18n/translation";
|
||||
import I18nKey from "../../i18n/i18nKey";
|
||||
import {getPostUrlBySlug} from "../../utils/url-utils";
|
||||
|
||||
let posts = await getSortedPosts()
|
||||
|
||||
const LIMIT = 3;
|
||||
|
||||
posts = posts.slice(0, LIMIT)
|
||||
|
||||
---
|
||||
<WidgetLayout name={i18n(I18nKey.recentPosts)}>
|
||||
{posts.map(post =>
|
||||
<ButtonLink url={getPostUrlBySlug(post.slug)}>{post.data.title}</ButtonLink>
|
||||
)}
|
||||
</WidgetLayout>
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
import Profile from "./Profile.astro";
|
||||
import RecentPost from "./RecentPost.astro";
|
||||
import Tag from "./Tags.astro";
|
||||
import Categories from "./Categories.astro";
|
||||
|
||||
@@ -12,10 +11,6 @@ const className = Astro.props.class;
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-4 top-4 sticky top-4" transition:animate="none">
|
||||
<Categories></Categories>
|
||||
<!--<RecentPost></RecentPost>-->
|
||||
<Tag></Tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
---
|
||||
import Button from "../control/Button.astro";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import {i18n} from "../../i18n/translation";
|
||||
import I18nKey from "../../i18n/i18nKey";
|
||||
@@ -26,11 +25,11 @@ const {
|
||||
<slot></slot>
|
||||
</div>
|
||||
{isCollapsed && <div class="expand-btn px-4 -mb-2">
|
||||
<Button light class=" w-full rounded-lg" height="36px">
|
||||
<button class="btn-plain w-full h-9 rounded-lg">
|
||||
<div class="text-[var(--primary)] flex items-center justify-center gap-2 -translate-x-2">
|
||||
<Icon name="material-symbols:more-horiz" size={28}></Icon> {i18n(I18nKey.more)}
|
||||
</div>
|
||||
</Button>
|
||||
</button>
|
||||
</div>}
|
||||
</widget-layout>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user