feat: allow collapsing widget content, add categories widget

(cherry picked from commit 9a4ca8f6163d5e1375aa7c612e1338cce5a8c0b5)
This commit is contained in:
saicaca
2023-10-11 22:29:23 +08:00
parent 83b765a398
commit f4dc88e982
16 changed files with 174 additions and 33 deletions

View File

@@ -7,7 +7,8 @@ interface Props {
const { keyword, tags, categories} = Astro.props;
import Button from "./control/Button.astro";
import {getPostUrlBySlug, getSortedPosts} from "../utils/content-utils";
import {getSortedPosts} from "../utils/content-utils";
import {getPostUrlBySlug} from "../utils/url-utils";
let posts = await getSortedPosts()

View File

@@ -19,10 +19,10 @@ function getLinkName(name: string) {
}
---
<div class:list={[
<div transition:animate="none" 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 rounded-lg" light>
"card-base sticky top-0 overflow-visible max-w-[var(--page-width)] h-[72px] rounded-t-none mx-auto flex items-center justify-between px-4"]}>
<a href="/page/1"><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" />
{getConfig().title}

View File

@@ -0,0 +1,33 @@
---
import WidgetLayout from "./WidgetLayout.astro";
import {i18n} from "../../i18n/translation";
import I18nKey from "../../i18n/i18nKey";
import {CategoryMap, getCategoryMap} from "../../utils/content-utils";
import CategoriesLink from "./CategoriesLink.astro";
const categories = await getCategoryMap();
const COLLAPSED_HEIGHT = "120px";
const COLLAPSE_THRESHOLD = 5;
function count(categoryMap: CategoryMap): number {
let res = 0;
for (const key in categoryMap) {
res++;
res += count(categoryMap[key].children);
}
return res;
}
const isCollapsed = count(categories) >= COLLAPSE_THRESHOLD;
interface Props {
categories: CategoryMap;
}
---
<WidgetLayout name={i18n(I18nKey.categories)} id="categories" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT}>
<CategoriesLink categories={categories}></CategoriesLink>
</WidgetLayout>

View File

@@ -0,0 +1,21 @@
---
import {CategoryMap} from "../../utils/content-utils";
import {getCategoryUrl} from "../../utils/url-utils";
import ButtonLink from "../control/ButtonLink.astro";
interface Props {
categories: CategoryMap;
}
const {categories} = Astro.props;
---
<div>
{Object.entries(categories).map(([key, value]) =>
<ButtonLink url={getCategoryUrl(key)} badge={value.count}>{value.name}</ButtonLink>
<div class="ml-2">
{Object.keys(value.children).length > 0 && <Astro.self categories={value.children}></Astro.self>}
</div>
)}
</div>

View File

@@ -1,17 +1,17 @@
---
import WidgetLayout from "./WidgetLayout.astro";
import ButtonLink from "../control/ButtonLink.astro";
import {getPostUrlBySlug, getSortedPosts} from "../../utils/content-utils";
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 = 5;
const LIMIT = 3;
posts = posts.slice(0, LIMIT)
// console.log(posts)
---
<WidgetLayout name={i18n(I18nKey.recentPosts)}>
{posts.map(post =>

View File

@@ -1,14 +1,20 @@
---
import Profile from "./Profile.astro";
import RecentPost from "./RecentPost.astro";
import Tag from "./Tag.astro";
import Tag from "./Tags.astro";
import Categories from "./Categories.astro";
const className = Astro.props.class;
---
<div id="sidebar" class:list={[className, "flex flex-col w-full gap-4"]} transition:persist>
<Profile></Profile>
<RecentPost></RecentPost>
<Tag></Tag>
<div id="sidebar" class:list={[className, "w-full"]} transition:persist>
<div class="flex flex-col w-full gap-4 mb-4">
<Profile></Profile>
</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>

View File

@@ -8,8 +8,12 @@ import I18nKey from "../../i18n/i18nKey";
const tags = await getTagList();
const COLLAPSED_HEIGHT = "120px";
const isCollapsed = tags.length >= 20;
---
<WidgetLayout name={i18n(I18nKey.tags)}>
<WidgetLayout name={i18n(I18nKey.tags)} id="tags" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT}>
<div class="flex gap-2 flex-wrap">
{tags.map(t => (
<ButtonTag href={`/archive/tag/${t.name}`}>

View File

@@ -1,18 +1,62 @@
---
import Button from "../control/Button.astro";
import { Icon } from 'astro-icon/components';
import {i18n} from "../../i18n/translation";
import I18nKey from "../../i18n/i18nKey";
interface Props {
id: string;
name?: string;
isCollapsed?: boolean;
collapsedHeight?: string;
}
const props = Astro.props;
const {
id,
name,
isCollapsed,
collapsedHeight,
} = Astro.props
---
<div class="pb-4 card-base">
<div class="font-bold text-lg text-neutral-900 dark:text-neutral-100 transition relative ml-8 mt-4 mb-2
<widget-layout data-id={id} data-isCollapsed={isCollapsed} class="pb-4 card-base">
<div class="font-bold transition text-lg text-neutral-900 dark:text-neutral-100 relative ml-8 mt-4 mb-2
before:w-1 before:h-4 before:rounded-md before:bg-[var(--primary)]
before:absolute before:left-[-16px] before:top-[5.5px]">{name}</div>
<div class="px-4">
<div id={id} class:list={["collapse-wrapper px-4 overflow-hidden", {"collapsed": isCollapsed}]}>
<slot></slot>
</div>
</div>
{isCollapsed && <div class="expand-btn px-4 -mb-2">
<Button light class=" w-full rounded-lg" height="36px">
<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>
</div>}
</widget-layout>
<style define:vars={{ collapsedHeight }}>
.collapsed {
height: var(--collapsedHeight);
}
</style>
<script>
class WidgetLayout extends HTMLElement {
constructor() {
super();
if (!this.dataset.isCollapsed)
return;
const id = this.dataset.id;
const btn = this.querySelector('.expand-btn');
const wrapper = this.querySelector(`#${id}`)
btn.addEventListener('click', () => {
wrapper.classList.remove('collapsed');
btn.classList.add('hidden');
})
}
}
customElements.define('widget-layout', WidgetLayout);
</script>