feat: use .ts instead of .yaml for configurations

This commit is contained in:
saicaca 2023-10-23 17:45:07 +08:00
parent 9f213d525f
commit 1ae4a8eee9
23 changed files with 4259 additions and 375 deletions

View File

@ -22,7 +22,7 @@ Fuwari (not the final name maybe) is a static blog template built with [Astro](h
## 🚀 How to Use
1. Fork this repo.
2. Edit the config file `fuwari.config.yml` to customize your blog.
2. Edit the config file `src/config.ts` to customize your blog.
3. Run `npm run new-post -- <filename>` to create a new post and edit it in `src/content/posts/`.
4. Deploy your blog to Vercel, Netlify, GitHub Pages, etc. following [the guides](https://docs.astro.build/en/guides/deploy/).

View File

@ -1,29 +0,0 @@
title: Fuwari
menu:
home: /page/1
archive: /archive
about: /about
appearance:
hue: 250
lang: en
banner:
enable: true
url: /images/demo-banner.jpg
profile:
avatar: https://saicaca.github.io/vivia-preview/assets/avatar.jpg
author: Your Name
subtitle: This is the subtitle
links:
- name: Twitter
icon: fa6-brands:twitter
url: https://twitter.com
- name: Steam
icon: fa6-brands:steam
url: https://store.steampowered.com
- name: GitHub
icon: fa6-brands:github
url: https://github.com/saicaca/fuwari

4293
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@
"reading-time": "^1.5.0",
"rehype-katex": "^7.0.0",
"remark-math": "^6.0.0",
"sharp": "^0.32.6",
"tailwindcss": "^3.3.3",
"typescript": "^5.2.2",
"valine": "^1.5.1"

View File

@ -38,6 +38,9 @@ dependencies:
remark-math:
specifier: ^6.0.0
version: 6.0.0
sharp:
specifier: ^0.32.6
version: 0.32.6
tailwindcss:
specifier: ^3.3.3
version: 3.3.3
@ -1706,7 +1709,6 @@ packages:
resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
requiresBuild: true
dev: false
optional: true
/bail@2.0.2:
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
@ -1744,7 +1746,6 @@ packages:
inherits: 2.0.4
readable-stream: 3.6.2
dev: false
optional: true
/bl@5.1.0:
resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==}
@ -1810,7 +1811,6 @@ packages:
base64-js: 1.5.1
ieee754: 1.2.1
dev: false
optional: true
/buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
@ -1932,7 +1932,6 @@ packages:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
requiresBuild: true
dev: false
optional: true
/chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
@ -2018,7 +2017,6 @@ packages:
color-name: 1.1.4
simple-swizzle: 0.2.2
dev: false
optional: true
/color@4.2.3:
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
@ -2028,7 +2026,6 @@ packages:
color-convert: 2.0.1
color-string: 1.9.1
dev: false
optional: true
/colorjs.io@0.4.5:
resolution: {integrity: sha512-yCtUNCmge7llyfd/Wou19PMAcf5yC3XXhgFoAh6zsO2pGswhUPBaaUh8jzgHnXtXuZyFKzXZNAnyF5i+apICow==}
@ -2216,14 +2213,12 @@ packages:
dependencies:
mimic-response: 3.1.0
dev: false
optional: true
/deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
requiresBuild: true
dev: false
optional: true
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
@ -2240,7 +2235,6 @@ packages:
engines: {node: '>=8'}
requiresBuild: true
dev: false
optional: true
/devalue@4.3.2:
resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==}
@ -2492,7 +2486,6 @@ packages:
engines: {node: '>=6'}
requiresBuild: true
dev: false
optional: true
/extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
@ -2523,7 +2516,6 @@ packages:
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
requiresBuild: true
dev: false
optional: true
/fast-glob@3.3.1:
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
@ -2628,7 +2620,6 @@ packages:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
requiresBuild: true
dev: false
optional: true
/fs-minipass@2.1.0:
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
@ -2691,7 +2682,6 @@ packages:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
requiresBuild: true
dev: false
optional: true
/github-slugger@2.0.0:
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
@ -2998,7 +2988,6 @@ packages:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
requiresBuild: true
dev: false
optional: true
/insane@2.6.2:
resolution: {integrity: sha512-BqEL1CJsjJi+/C/zKZxv31zs3r6zkLH5Nz1WMFb7UBX2KHY2yXDpbFTSEmNHzomBbGDysIfkTX55A0mQZ2CQiw==}
@ -3016,7 +3005,6 @@ packages:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
requiresBuild: true
dev: false
optional: true
/is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
@ -4066,7 +4054,6 @@ packages:
engines: {node: '>=10'}
requiresBuild: true
dev: false
optional: true
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@ -4077,7 +4064,6 @@ packages:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
requiresBuild: true
dev: false
optional: true
/minipass@3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
@ -4112,7 +4098,6 @@ packages:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
requiresBuild: true
dev: false
optional: true
/mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
@ -4155,7 +4140,6 @@ packages:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
requiresBuild: true
dev: false
optional: true
/needle@2.9.1:
resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==}
@ -4182,13 +4166,11 @@ packages:
dependencies:
semver: 7.5.4
dev: false
optional: true
/node-addon-api@6.1.0:
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
requiresBuild: true
dev: false
optional: true
/node-releases@2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
@ -4501,7 +4483,6 @@ packages:
tar-fs: 2.1.1
tunnel-agent: 0.6.0
dev: false
optional: true
/preferred-pm@3.1.2:
resolution: {integrity: sha512-nk7dKrcW8hfCZ4H6klWcdRknBOXWzNQByJ0oJyX97BOupsYD+FzLS4hflgEu/uPUEHZCuRfMxzCBsuWd7OzT8Q==}
@ -4580,7 +4561,6 @@ packages:
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
requiresBuild: true
dev: false
optional: true
/rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
@ -4592,7 +4572,6 @@ packages:
minimist: 1.2.8
strip-json-comments: 2.0.1
dev: false
optional: true
/read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
@ -4882,7 +4861,6 @@ packages:
tar-fs: 3.0.4
tunnel-agent: 0.6.0
dev: false
optional: true
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
@ -4926,7 +4904,6 @@ packages:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
requiresBuild: true
dev: false
optional: true
/simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
@ -4936,7 +4913,6 @@ packages:
once: 1.4.0
simple-concat: 1.0.1
dev: false
optional: true
/simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
@ -4944,7 +4920,6 @@ packages:
dependencies:
is-arrayish: 0.3.2
dev: false
optional: true
/sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
@ -4992,7 +4967,6 @@ packages:
fast-fifo: 1.3.2
queue-tick: 1.0.1
dev: false
optional: true
/string-width@1.0.2:
resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==}
@ -5100,7 +5074,6 @@ packages:
engines: {node: '>=0.10.0'}
requiresBuild: true
dev: false
optional: true
/stylus@0.59.0:
resolution: {integrity: sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==}
@ -5251,7 +5224,6 @@ packages:
pump: 3.0.0
tar-stream: 2.2.0
dev: false
optional: true
/tar-fs@3.0.4:
resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==}
@ -5261,7 +5233,6 @@ packages:
pump: 3.0.0
tar-stream: 3.1.6
dev: false
optional: true
/tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
@ -5274,7 +5245,6 @@ packages:
inherits: 2.0.4
readable-stream: 3.6.2
dev: false
optional: true
/tar-stream@3.1.6:
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
@ -5284,7 +5254,6 @@ packages:
fast-fifo: 1.3.2
streamx: 2.15.1
dev: false
optional: true
/tar@6.2.0:
resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==}
@ -5353,7 +5322,6 @@ packages:
dependencies:
safe-buffer: 5.2.1
dev: false
optional: true
/type-fest@0.13.1:
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

View File

Before

Width:  |  Height:  |  Size: 877 KiB

After

Width:  |  Height:  |  Size: 877 KiB

View File

@ -1,8 +1,8 @@
---
import {getConfig} from "../utils/config-utils";
import {siteConfig} from "../config";
---
<div id="config-carrier" data-hue={getConfig().appearance.hue}>
<div id="config-carrier" data-hue={siteConfig.themeHue}>
</div>

View File

@ -1,12 +1,12 @@
---
import {getConfig} from "../utils/config-utils";
import {profileConfig} from "../config";
---
<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 {getConfig().profile.author}. All Rights Reserved.
© 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>
</div>

View File

@ -75,6 +75,8 @@ color_set({
--deep-text: oklch(0.25 0.02 var(--hue))
--title-active: oklch(0.6 0.1 var(--hue))
--line-divider: black(0.08) white(0.08)
--line-color: black(0.1) white(0.1)

View File

@ -2,20 +2,41 @@
import Button from "./control/Button.astro";
import { Icon } from 'astro-icon/components';
import DisplaySetting from "./widget/DisplaySetting.astro";
import {getConfig} from "../utils/config-utils";
import I18nKey from "../i18n/i18nKey";
import {i18n} from "../i18n/translation";
import {LinkPreset, NavBarLink} from "../types/config";
import {navBarConfig, siteConfig} from "../config";
const className = Astro.props.class;
function isI18nKey(key: string): key is I18nKey {
return Object.values(I18nKey).includes(key);
}
function getLinkName(name: string) {
if (isI18nKey(name)) {
return i18n(name);
let links: NavBarLink[] = navBarConfig.links.map((item) => {
if (typeof item === "number") {
return getLinkPresetInfo(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"
};
}
return name;
}
---
@ -25,12 +46,12 @@ function getLinkName(name: string) {
<a href="/page/1"><Button height="52px" class="px-5 font-bold rounded-lg active:scale-95" 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}
{siteConfig.title}
</div>
</Button></a>
<div>
{Object.keys(getConfig().menu).map((key) => {
return <a aria-label={getLinkName(key)} href={getConfig().menu[key]}><Button light class="font-bold px-5 rounded-lg active:scale-95">{getLinkName(key)}</Button></a>
{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">{l.name}</Button></a>;
})}
</div>
<div class="flex">

View File

@ -35,6 +35,7 @@ const { remarkPluginFrontmatter } = await entry.render();
class="transition w-full block font-bold mb-3 text-3xl
text-black/90 dark:text-white/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)]
before:absolute md:before:top-[35px] before:left-[18px]
">
@ -44,7 +45,7 @@ const { remarkPluginFrontmatter } = await entry.render();
<!-- metadata -->
<PostMetadata published={published} 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">
<div class="transition text-black/75 dark:text-white/75 mb-3.5">
{ description }
</div>
@ -61,8 +62,8 @@ const { remarkPluginFrontmatter } = await entry.render();
"max-h-[20vh] md:max-h-none mx-4 mt-4 md:mx-0 md:mt-0",
"md:w-[var(--coverWidth)] relative md:absolute md:top-3 md:bottom-3 md:right-3 rounded-xl overflow-hidden active:scale-95"
]} >
<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 pointer-events-none z-10 w-full h-full group-hover:bg-black/30 group-active:bg-black/50 transition"></div>
<div class="absolute pointer-events-none 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>

View File

@ -5,11 +5,23 @@ interface Props {
class?: string;
alt?: string
}
import { Image } from 'astro:assets';
const {id, src, alt} = Astro.props;
const className = Astro.props.class;
const isLocal = !(src.startsWith('/') || src.startsWith('http') || src.startsWith('https') || src.startsWith('data:'));
let img;
if (isLocal) {
img = (await import("../../" + src)).default;
}
---
<div class:list={[className, 'overflow-hidden relative']}>
<div class="transition absolute inset-0 dark:bg-black/10 bg-opacity-50"></div>
<img src={src} alt={alt} class="w-full h-full object-center object-cover">
<div class="transition absolute inset-0 dark:bg-black/10 bg-opacity-50 pointer-events-none"></div>
{isLocal && <Image src={img} alt={alt || ""} class="w-full h-full object-center object-cover" />}
{!isLocal && <img src={src} alt={alt || ""} class="w-full h-full object-center object-cover" />}
</div>

View File

@ -1,9 +1,9 @@
---
import {getConfig} from "../../utils/config-utils";
import {i18n} from "../../i18n/translation";
import I18nKey from "../../i18n/i18nKey";
import {siteConfig} from "../../config";
const enableBanner = getConfig().banner.enable;
const enableBanner = siteConfig.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",

View File

@ -1,30 +1,30 @@
---
import ImageBox from "../misc/ImageBox.astro";
import Button from "../control/Button.astro";
import {getConfig} from "../../utils/config-utils";
import {Icon} from "astro-icon/components";
import {profileConfig} from "../../config";
interface props {
}
const className = Astro.props
const vConf = getConfig();
const config = profileConfig;
---
<div class="card-base">
<a aria-label="Go to About Page" href="/about" class="group block relative m-3 overflow-hidden rounded-xl active:scale-95">
<div class="absolute transition group-hover:bg-black/30 group-active:bg-black/50 w-full h-full z-50 flex items-center justify-center">
<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="material-symbols:person-outline-rounded"
class="transition opacity-0 group-hover:opacity-100 text-white text-6xl">
</Icon>
</div>
<ImageBox src={vConf.profile.avatar} alt="Profile Image of the Author" class="mt-1 mx-auto w-[240px] lg:w-full h-full lg:mt-0 "></ImageBox>
<ImageBox src={config.avatar} alt="Profile Image of the Author" class="mt-1 mx-auto w-[240px] lg:w-full h-full lg:mt-0 "></ImageBox>
</a>
<div class="font-bold text-xl text-center mb-1 dark:text-neutral-50 transition">{vConf.profile.author}</div>
<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-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">{config.bio}</div>
<div class="flex gap-2 mx-2 justify-center mb-4">
{vConf.profile.links.map(item =>
{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>

47
src/config.ts Normal file
View File

@ -0,0 +1,47 @@
import type {NavBarConfig, ProfileConfig, SiteConfig} from "./types/config.ts";
import {LinkPreset} from "./types/config.ts";
export const siteConfig: SiteConfig = {
title: 'Fuwari',
subtitle: 'Demo Site',
lang: 'en-US',
themeHue: 250,
banner: {
enable: true,
src: 'assets/images/demo-banner.png',
}
}
export const navBarConfig: NavBarConfig = {
links: [
LinkPreset.Home,
LinkPreset.Archive,
LinkPreset.About,
{
name: 'GitHub',
url: 'https://github.com/saicaca/fuwari',
external: true,
}
]
}
export const profileConfig: ProfileConfig = {
avatar: 'assets/images/demo-avatar.png',
name: 'Lorem Ipsum',
bio: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
links: [
{
name: 'Twitter',
icon: 'fa6-brands:twitter',
url: 'https://twitter.com',
}, {
name: 'Steam',
icon: 'fa6-brands:steam',
url: 'https://store.steampowered.com',
}, {
name: 'GitHub',
icon: 'fa6-brands:github',
url: 'https://github.com/saicaca/fuwari',
}
]
}

View File

@ -6,16 +6,17 @@ image: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/208fc754-890d-4adb-9753
tags: ["Fuwari", "Blogging", "Customization"]
---
# How to set a cover image using the cover attribute
## Set the cover image using the `image` attribute
Select an Image: Before you start, make sure you have an image you want to use as a cover. Let's assume its filename is my-cover-image.jpg and it's located in an images directory at the root of your site.
Edit your article: At the top of your Markdown file, include the frontmatter section. Add a cover attribute and specify the path to your cover image.
Edit your article: At the top of your Markdown file, include the frontmatter section. Set the `image` attribute to the path of your image file.
```markdown
---
title: "Your Article Title"
published: 2023-10-05
cover: "/images/my-cover-image.jpg"
image: "/images/my-cover-image.jpg"
---
```
Web URLs are also supported.

View File

@ -2,7 +2,7 @@ import {en} from "./languages/en.ts";
import {zh_TW} from "./languages/zh_TW.ts";
import {zh_CN} from "./languages/zh_CN.ts";
import type I18nKey from "./i18nKey.ts";
import {getConfig} from "../utils/config-utils.ts";
import {siteConfig} from "../config.ts";
export type Translation = {
[K in I18nKey]: string;
@ -25,6 +25,6 @@ export function getTranslation(lang: string): Translation {
}
export function i18n(key: I18nKey): string {
const lang = getConfig().lang || "en";
const lang = siteConfig.lang || "en";
return getTranslation(lang)[key];
}

View File

@ -7,9 +7,9 @@ import { ViewTransitions } from 'astro:transitions';
import ImageBox from "../components/misc/ImageBox.astro";
import { fade } from 'astro:transitions';
import {getConfig} from "../utils/config-utils";
import {pathsEqual} from "../utils/url-utils";
import ConfigCarrier from "../components/ConfigCarrier.astro";
import {siteConfig} from "../config";
interface Props {
title: string;
@ -46,18 +46,19 @@ 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 configHue = viConf.appearance.hue;
const configHue = siteConfig.themeHue;
if (!banner || typeof banner !== 'string' || banner.trim() === '') {
banner = viConf.banner.url;
banner = siteConfig.banner.src;
}
// TODO don't use post cover as banner for now
banner = viConf.banner.url;
banner = siteConfig.banner.src;
let pageTitle = getConfig().title;
let pageTitle;
if (title) {
pageTitle = `${title} - ${pageTitle}`;
pageTitle = `${title} - ${siteConfig.title}`;
} else {
pageTitle = `${siteConfig.title} - ${siteConfig.subtitle}`;
}
---
@ -94,8 +95,8 @@ if (title) {
class:list={{'banner-home': isHomePage, 'banner-else': !isHomePage}}
>
<ImageBox id="boxtest" alt="Banner image of the blog" class:list={["object-center object-cover h-full", {"hidden": !viConf.banner.enable}]}
src={banner} transition:animate="fade"
<ImageBox id="boxtest" alt="Banner image of the blog" class:list={["object-center object-cover h-full", {"hidden": !siteConfig.banner.enable}]}
src={siteConfig.banner.src} transition:animate="fade"
>
</ImageBox>
</div>

View File

@ -6,7 +6,7 @@ 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";
import {siteConfig} from "../config";
interface Props {
title: string;
@ -17,8 +17,7 @@ const { title, banner } = Astro.props;
const isHomePage = pathsEqual(Astro.url.pathname, '/') || pathsEqual(Astro.url.pathname, '/page/1');
const enableBanner = getConfig().banner.enable;
const enableBanner = siteConfig.banner.enable;
---

View File

@ -5,7 +5,6 @@ import ImageBox from "../../components/misc/ImageBox.astro";
import {Icon} from "astro-icon/components";
import PostMetadata from "../../components/PostMetadata.astro";
import Button from "../../components/control/Button.astro";
import {getConfig} from "../../utils/config-utils";
import {i18n} from "../../i18n/translation";
import I18nKey from "../../i18n/i18nKey";
import {getPostUrlBySlug} from "../../utils/url-utils";
@ -109,16 +108,30 @@ const { remarkPluginFrontmatter } = await entry.render();
<style lang="stylus" is:global>
.custom-md
a
position: relative
background: none
margin: -4px
padding: 4px
border-radius: 6px
color: var(--primary)
text-decoration none
text-decoration-line: none;
/*&:after*/
/* content: ''*/
/* position: absolute*/
/* left: 2px*/
/* right: 2px*/
/* bottom: 4px*/
/* height: 6px*/
/* border-radius: 3px*/
/* background: var(--link-hover)*/
/* transition: background 0.15s ease-in-out;*/
/* z-index: -1;*/
&:hover
background: var(--link-hover)
&:active
background: var(--link-active)
/*&:after*/
/* background: var(--link-active)*/
code
font-family: monospace
background: var(--inline-code-bg)
@ -132,6 +145,9 @@ const { remarkPluginFrontmatter } = await entry.render();
content: none
pre
background: var(--codeblock-bg) !important
border-radius: 12px
padding-left: 20px
padding-right: 20px
code
padding: 0
background: none
@ -172,7 +188,7 @@ const { remarkPluginFrontmatter } = await entry.render();
border-color: var(--line-divider)
border-style: dashed
iframe
border-radius: 8px
border-radius: 12px
margin-left: auto
margin-right: auto
max-width: 100%

39
src/types/config.ts Normal file
View File

@ -0,0 +1,39 @@
export type SiteConfig = {
title: string,
subtitle: string,
lang: string,
themeHue: number,
banner: {
enable: boolean,
src: string,
}
};
export enum LinkPreset {
Home,
Archive,
About,
}
export type NavBarLink = {
name: string,
url: string,
external?: boolean
}
export type NavBarConfig = {
links: (NavBarLink | LinkPreset)[],
}
export type ProfileConfig = {
avatar?: string,
name: string,
bio?: string,
links: {
name: string,
url: string,
icon: string,
}[],
};

View File

@ -1,40 +0,0 @@
// @ts-ignore
import _config from '../../fuwari.config.yml';
interface FuwariConfig {
title: string;
menu: {
[key: string]: string;
};
lang: string;
appearance: {
hue: number;
};
favicon: string;
banner: {
enable: boolean;
url: string;
position: string;
onAllPages: boolean;
};
sidebar: {
widgets: {
normal: string | string[];
sticky: string | string[];
};
};
profile: {
avatar: string;
author: string;
subtitle: string;
links: {
name: string;
icon: string;
url: string;
}[];
}
}
const config: FuwariConfig = _config;
export const getConfig = () => config;