fix: make `base` in astro config work

This commit is contained in:
saicaca 2024-04-29 15:56:28 +08:00
parent 9a3119cab4
commit 410902a767
11 changed files with 37 additions and 26 deletions

View File

@ -26,6 +26,7 @@ const oklchToHex = (str) => {
export default defineConfig({ export default defineConfig({
site: "https://fuwari.vercel.app/", site: "https://fuwari.vercel.app/",
base: "/", base: "/",
trailingSlash: "always",
integrations: [ integrations: [
tailwind(), tailwind(),
swup({ swup({

View File

@ -7,6 +7,7 @@ import NavMenuPanel from "./widget/NavMenuPanel.astro";
import Search from "./Search.svelte"; import Search from "./Search.svelte";
import {LinkPresets} from "../constants/link-presets"; import {LinkPresets} from "../constants/link-presets";
import LightDarkSwitch from "./LightDarkSwitch.svelte"; import LightDarkSwitch from "./LightDarkSwitch.svelte";
import {url} from "../utils/url-utils";
const className = Astro.props.class; const className = Astro.props.class;
let links: NavBarLink[] = navBarConfig.links.map((item: NavBarLink | LinkPreset): NavBarLink => { let links: NavBarLink[] = navBarConfig.links.map((item: NavBarLink | LinkPreset): NavBarLink => {
@ -20,7 +21,7 @@ let links: NavBarLink[] = navBarConfig.links.map((item: NavBarLink | LinkPreset)
<div class:list={[ <div class:list={[
className, 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"]}> "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="/" class="btn-plain h-[3.25rem] px-5 font-bold rounded-lg active:scale-95"> <a href={url('/')} 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"> <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" /> <Icon name="material-symbols:home-outline-rounded" size={"1.75rem"} class="mb-1 mr-2" />
{siteConfig.title} {siteConfig.title}
@ -28,7 +29,7 @@ let links: NavBarLink[] = navBarConfig.links.map((item: NavBarLink | LinkPreset)
</a> </a>
<div class="hidden md:flex"> <div class="hidden md:flex">
{links.map((l) => { {links.map((l) => {
return <a aria-label={l.name} href={l.url} target={l.external ? "_blank" : null} return <a aria-label={l.name} href={l.external ? l.url : url(l.url)} target={l.external ? "_blank" : null}
class="btn-plain h-11 font-bold px-5 rounded-lg active:scale-95" class="btn-plain h-11 font-bold px-5 rounded-lg active:scale-95"
> >
<div class="flex items-center"> <div class="flex items-center">
@ -101,9 +102,9 @@ document.addEventListener('astro:after-swap', () => {
}, { once: false }); }, { once: false });
</script> </script>
{import.meta.env.PROD && <script is:raw> {import.meta.env.PROD && <script is:inline define:vars={{scriptUrl: url('/pagefind/pagefind.js')}}>
async function loadPagefind() { async function loadPagefind() {
const pagefind = await import('/pagefind/pagefind.js') const pagefind = await import(scriptUrl)
await pagefind.options({ await pagefind.options({
'excerptLength': 20 'excerptLength': 20
}) })

View File

@ -3,6 +3,7 @@ import {formatDateToYYYYMMDD} from "../utils/date-utils";
import { Icon } from 'astro-icon/components'; import { Icon } from 'astro-icon/components';
import {i18n} from "../i18n/translation"; import {i18n} from "../i18n/translation";
import I18nKey from "../i18n/i18nKey"; import I18nKey from "../i18n/i18nKey";
import {url} from "../utils/url-utils";
interface Props { interface Props {
class: string; class: string;
@ -32,7 +33,7 @@ const className = Astro.props.class;
<Icon name="material-symbols:menu-rounded" class="text-xl"></Icon> <Icon name="material-symbols:menu-rounded" class="text-xl"></Icon>
</div> </div>
<div class="flex flex-row flex-nowrap"> <div class="flex flex-row flex-nowrap">
<div><a href=`/archive/category/${category || 'uncategorized'}` aria-label=`View all posts in the ${category} category` <div><a href={url(`/archive/category/${category || 'uncategorized'}/`)} aria-label=`View all posts in the ${category} category`
class="link-lg transition text-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"> hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
{category || i18n(I18nKey.uncategorized)} {category || i18n(I18nKey.uncategorized)}
@ -50,7 +51,7 @@ const className = Astro.props.class;
{(tags && tags.length > 0) && tags.map(tag => <div {(tags && tags.length > 0) && tags.map(tag => <div
class="with-divider" class="with-divider"
> >
<a href=`/archive/tag/${tag}` aria-label=`View all posts with the ${tag} tag` <a href={url(`/archive/tag/${tag}/`)} aria-label=`View all posts with the ${tag} tag`
class="link-lg transition text-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"> hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
{tag} {tag}

View File

@ -1,16 +1,17 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte' import { onMount } from 'svelte'
import {url} from "@utils/url-utils.ts"
let keywordDesktop = '' let keywordDesktop = ''
let keywordMobile = '' let keywordMobile = ''
let result = [] let result = []
const fakeResult = [{ const fakeResult = [{
url: '/', url: url('/'),
meta: { meta: {
title: 'This Is a Fake Search Result' title: 'This Is a Fake Search Result'
}, },
excerpt: 'Because the search cannot work in the <mark>dev</mark> environment.' excerpt: 'Because the search cannot work in the <mark>dev</mark> environment.'
}, { }, {
url: '/', url: url('/'),
meta: { meta: {
title: 'If You Want to Test the Search' title: 'If You Want to Test the Search'
}, },

View File

@ -1,6 +1,7 @@
--- ---
import type { Page } from "astro"; import type { Page } from "astro";
import { Icon } from 'astro-icon/components'; import { Icon } from 'astro-icon/components';
import {url} from "../../utils/url-utils";
interface Props { interface Props {
page: Page; page: Page;
class?: string; class?: string;
@ -49,19 +50,16 @@ if (r == page.lastPage - 2)
if (r < page.lastPage) if (r < page.lastPage)
pages.push(page.lastPage); pages.push(page.lastPage);
const parts: string[] = page.url.current.split('/');
const commonUrl: string = parts.slice(0, -1).join('/') + '/';
const getPageUrl = (p: number) => { const getPageUrl = (p: number) => {
if (p == 1) if (p == 1)
return commonUrl; return '/';
return commonUrl + p; return `/${p}/`;
} }
--- ---
<div class:list={[className, "flex flex-row gap-3 justify-center"]} style={style}> <div class:list={[className, "flex flex-row gap-3 justify-center"]} style={style}>
<a href={page.url.prev} aria-label={page.url.prev ? "Previous Page" : null} <a href={url(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", class:list={["btn-card overflow-hidden rounded-lg text-[var(--primary)] w-11 h-11",
{"disabled": page.url.prev == undefined} {"disabled": page.url.prev == undefined}
]} ]}
@ -78,12 +76,12 @@ const getPageUrl = (p: number) => {
> >
{p} {p}
</div> </div>
return <a href={getPageUrl(p)} aria-label=`Page ${p}` return <a href={url(getPageUrl(p))} aria-label=`Page ${p}`
class="btn-card w-11 h-11 rounded-lg overflow-hidden active:scale-[0.85]" class="btn-card w-11 h-11 rounded-lg overflow-hidden active:scale-[0.85]"
>{p}</a> >{p}</a>
})} })}
</div> </div>
<a href={page.url.next} aria-label={page.url.next ? "Next Page" : null} <a href={url(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", class:list={["btn-card overflow-hidden rounded-lg text-[var(--primary)] w-11 h-11",
{"disabled": page.url.next == undefined} {"disabled": page.url.next == undefined}
]} ]}

View File

@ -8,11 +8,13 @@ interface Props {
basePath?: string basePath?: string
} }
import { Image } from 'astro:assets'; import { Image } from 'astro:assets';
import {url} from "../../utils/url-utils";
const {id, src, alt, basePath = '/'} = Astro.props; const {id, src, alt, basePath = '/'} = Astro.props;
const className = Astro.props.class; const className = Astro.props.class;
const isLocal = !(src.startsWith('/') || src.startsWith('http') || src.startsWith('https') || src.startsWith('data:')); const isLocal = !(src.startsWith('/') || src.startsWith('http') || src.startsWith('https') || src.startsWith('data:'));
const isPublic = src.startsWith('/');
// TODO temporary workaround for images dynamic import // TODO temporary workaround for images dynamic import
// https://github.com/withastro/astro/issues/3373 // https://github.com/withastro/astro/issues/3373
@ -27,6 +29,6 @@ if (isLocal) {
<div class:list={[className, 'overflow-hidden relative']}> <div class:list={[className, 'overflow-hidden relative']}>
<div class="transition absolute inset-0 dark:bg-black/10 bg-opacity-50 pointer-events-none"></div> <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 && <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" />} {!isLocal && <img src={isPublic ? url(src) : src} alt={alt || ""} class="w-full h-full object-center object-cover" />}
</div> </div>

View File

@ -2,11 +2,12 @@
import ImageWrapper from "../misc/ImageWrapper.astro"; import ImageWrapper from "../misc/ImageWrapper.astro";
import {Icon} from "astro-icon/components"; import {Icon} from "astro-icon/components";
import {profileConfig} from "../../config"; import {profileConfig} from "../../config";
import {url} from "../../utils/url-utils";
const config = profileConfig; const config = profileConfig;
--- ---
<div class="card-base"> <div class="card-base">
<a aria-label="Go to About Page" href="/about" <a aria-label="Go to About Page" href={url('/about/')}
class="group block relative mx-auto mt-4 lg:mx-3 lg:mt-3 mb-3 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"> 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 <div class="absolute transition pointer-events-none group-hover:bg-black/30 group-active:bg-black/50

View File

@ -5,6 +5,7 @@ import ButtonTag from "../control/ButtonTag.astro";
import {getTagList} from "../../utils/content-utils"; import {getTagList} from "../../utils/content-utils";
import {i18n} from "../../i18n/translation"; import {i18n} from "../../i18n/translation";
import I18nKey from "../../i18n/i18nKey"; import I18nKey from "../../i18n/i18nKey";
import {url} from "../../utils/url-utils";
const tags = await getTagList(); const tags = await getTagList();
@ -23,7 +24,7 @@ const style = Astro.props.style
<WidgetLayout name={i18n(I18nKey.tags)} id="tags" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT} class={className} style={style}> <WidgetLayout name={i18n(I18nKey.tags)} id="tags" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT} class={className} style={style}>
<div class="flex gap-2 flex-wrap"> <div class="flex gap-2 flex-wrap">
{tags.map(t => ( {tags.map(t => (
<ButtonTag href={`/archive/tag/${t.name}`} label={`View all posts with the ${t.name} tag`}> <ButtonTag href={url(`/archive/tag/${t.name}/`)} label={`View all posts with the ${t.name} tag`}>
{t.name} {t.name}
</ButtonTag> </ButtonTag>
))} ))}

View File

@ -9,10 +9,10 @@ export const LinkPresets: { [key in LinkPreset]: NavBarLink } = {
}, },
[LinkPreset.About]: { [LinkPreset.About]: {
name: i18n(I18nKey.about), name: i18n(I18nKey.about),
url: '/about', url: '/about/',
}, },
[LinkPreset.Archive]: { [LinkPreset.Archive]: {
name: i18n(I18nKey.archive), name: i18n(I18nKey.archive),
url: '/archive', url: '/archive/',
}, },
} }

View File

@ -11,6 +11,7 @@ import {profileConfig, siteConfig} from "@/config";
import {Favicon} from "../types/config"; import {Favicon} from "../types/config";
import {defaultFavicons} from "../constants/icon"; import {defaultFavicons} from "../constants/icon";
import {LIGHT_MODE, DARK_MODE, AUTO_MODE, DEFAULT_THEME} from "../constants/constants"; import {LIGHT_MODE, DARK_MODE, AUTO_MODE, DEFAULT_THEME} from "../constants/constants";
import {url} from "../utils/url-utils";
interface Props { interface Props {
title: string; title: string;
@ -81,7 +82,7 @@ const favicons: Favicon[] = siteConfig.favicon.length > 0 ? siteConfig.favicon :
<meta name="generator" content={Astro.generator} /> <meta name="generator" content={Astro.generator} />
{favicons.map(favicon => ( {favicons.map(favicon => (
<link rel="icon" <link rel="icon"
href={favicon.src} href={favicon.src.startsWith('/') ? url(favicon.src) : favicon.src}
sizes={favicon.sizes} sizes={favicon.sizes}
media={favicon.theme && `(prefers-color-scheme: ${favicon.theme})`} media={favicon.theme && `(prefers-color-scheme: ${favicon.theme})`}
/> />

View File

@ -9,19 +9,19 @@ export function pathsEqual(path1: string, path2: string) {
function joinUrl(...parts: string[]): string { function joinUrl(...parts: string[]): string {
const joined = parts.join('/') const joined = parts.join('/')
return joined.replace(/([^:]\/)\/+/g, '$1') return joined.replace(/\/+/g, '/');
} }
export function getPostUrlBySlug(slug: string): string | null { export function getPostUrlBySlug(slug: string): string | null {
if (!slug) return null if (!slug) return null
return `/posts/${slug}` return url(`/posts/${slug}/`)
} }
export function getCategoryUrl(category: string): string | null { export function getCategoryUrl(category: string): string | null {
if (!category) return null if (!category) return null
if (category === i18n(i18nKey.uncategorized)) if (category === i18n(i18nKey.uncategorized))
return '/archive/category/uncategorized' return url('/archive/category/uncategorized/')
return `/archive/category/${category}` return url(`/archive/category/${category}/`)
} }
export function getDir(path: string): string { export function getDir(path: string): string {
@ -31,3 +31,7 @@ export function getDir(path: string): string {
} }
return path.substring(0, lastSlashIndex + 1) return path.substring(0, lastSlashIndex + 1)
} }
export function url(path: string) {
return joinUrl('', import.meta.env.BASE_URL, path)
}