From 51025f0ea72dbdc4e406d48b70e019427783d96b Mon Sep 17 00:00:00 2001 From: dabuside Date: Sun, 28 Jul 2024 01:41:11 +0800 Subject: [PATCH] feat: add photoswipe for image zoom (#135) --- astro.config.mjs | 16 ++-- package.json | 4 +- pnpm-lock.yaml | 9 +++ src/global.d.ts | 8 ++ src/layouts/Layout.astro | 55 +++++++------ src/layouts/MainGridLayout.astro | 23 +++--- src/pages/[...page].astro | 21 +++-- src/pages/posts/[...slug].astro | 132 ++++++++++++++++++++++--------- 8 files changed, 173 insertions(+), 95 deletions(-) create mode 100644 src/global.d.ts diff --git a/astro.config.mjs b/astro.config.mjs index 1c25fd8..b732012 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,22 +1,22 @@ +import sitemap from '@astrojs/sitemap'; +import svelte from "@astrojs/svelte" import tailwind from "@astrojs/tailwind" +import swup from '@swup/astro'; import Compress from "astro-compress" import icon from "astro-icon" import { defineConfig } from "astro/config" import Color from "colorjs.io" import rehypeAutolinkHeadings from "rehype-autolink-headings" +import rehypeComponents from "rehype-components"; /* Render the custom directive content */ import rehypeKatex from "rehype-katex" import rehypeSlug from "rehype-slug" -import remarkMath from "remark-math" -import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs" -import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs" -import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs" import remarkDirective from "remark-directive" /* Handle directives */ import remarkGithubAdmonitionsToDirectives from "remark-github-admonitions-to-directives"; -import rehypeComponents from "rehype-components"; /* Render the custom directive content */ -import svelte from "@astrojs/svelte" -import swup from '@swup/astro'; -import sitemap from '@astrojs/sitemap'; +import remarkMath from "remark-math" +import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs" +import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs" import {parseDirectiveNode} from "./src/plugins/remark-directive-rehype.js"; +import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs" const oklchToHex = (str) => { const DEFAULT_HUE = 250 diff --git a/package.json b/package.json index a36d54f..196e14f 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@types/markdown-it": "^14.1.2", "@types/mdast": "^4.0.4", "@types/sanitize-html": "^2.11.0", + "photoswipe": "^5.4.4", "remark-github-admonitions-to-directives": "^1.0.5", "sass": "^1.77.8", "stylus": "^0.63.0" @@ -67,5 +68,6 @@ "vite-imagetools": "^6.2.7", "sharp": "^0.33.0" } - } + }, + "packageManager": "pnpm@9.6.0+sha512.38dc6fba8dba35b39340b9700112c2fe1e12f10b17134715a4aa98ccf7bb035e76fd981cf0bb384dfa98f8d6af5481c2bef2f4266a24bfa20c34eb7147ce0b5e" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cfb2ba7..bad8cb1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,6 +142,9 @@ importers: '@types/sanitize-html': specifier: ^2.11.0 version: 2.11.0 + photoswipe: + specifier: ^5.4.4 + version: 5.4.4 remark-github-admonitions-to-directives: specifier: ^1.0.5 version: 1.0.5 @@ -3514,6 +3517,10 @@ packages: periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} + photoswipe@5.4.4: + resolution: {integrity: sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA==} + engines: {node: '>= 0.12.0'} + picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} @@ -8761,6 +8768,8 @@ snapshots: estree-walker: 3.0.3 is-reference: 3.0.2 + photoswipe@5.4.4: {} + picocolors@1.0.1: {} picomatch@2.3.1: {} diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..3584d67 --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,8 @@ +import type { AstroIntegration } from '@swup/astro' + +declare global { + interface Window { + // type from '@swup/astro' is incorrect + swup: AstroIntegration + } +} diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index b258198..4eaed38 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -1,53 +1,58 @@ --- -import GlobalStyles from "@components/GlobalStyles.astro"; -import '@fontsource/roboto/400.css'; -import '@fontsource/roboto/500.css'; -import '@fontsource/roboto/700.css'; -import ImageWrapper from "@components/misc/ImageWrapper.astro"; +import GlobalStyles from '@components/GlobalStyles.astro' +import '@fontsource/roboto/400.css' +import '@fontsource/roboto/500.css' +import '@fontsource/roboto/700.css' +import ImageWrapper from '@components/misc/ImageWrapper.astro' -import ConfigCarrier from "@components/ConfigCarrier.astro"; -import {profileConfig, siteConfig} from "@/config"; -import {type Favicon} from "../types/config"; -import {defaultFavicons} from "../constants/icon"; -import {LIGHT_MODE, DARK_MODE, AUTO_MODE, DEFAULT_THEME} from "../constants/constants"; -import {pathsEqual, url} from "../utils/url-utils"; +import { profileConfig, siteConfig } from '@/config' +import ConfigCarrier from '@components/ConfigCarrier.astro' +import { + AUTO_MODE, + DARK_MODE, + DEFAULT_THEME, + LIGHT_MODE, +} from '../constants/constants' +import { defaultFavicons } from '../constants/icon' +import type { Favicon } from '../types/config' +import { url, pathsEqual } from '../utils/url-utils' interface Props { - title?: string; - banner?: string; - description?: string; + title?: string + banner?: string + description?: string } -let { title, banner, description } = Astro.props; +let { title, banner, description } = Astro.props // apply a class to the body element to decide the height of the banner, only used for initial page load // Swup can update the body for each page visit, but it's after the page transition, causing a delay for banner height change // so use Swup hooks instead to change the height immediately when a link is clicked -const isHomePage = pathsEqual(Astro.url.pathname, url('/')); +const isHomePage = pathsEqual(Astro.url.pathname, url('/')) // defines global css variables // why doing this in Layout instead of GlobalStyles: https://github.com/withastro/astro/issues/6728#issuecomment-1502203757 -const configHue = siteConfig.themeColor.hue; +const configHue = siteConfig.themeColor.hue if (!banner || typeof banner !== 'string' || banner.trim() === '') { - banner = siteConfig.banner.src; + banner = siteConfig.banner.src } // TODO don't use post cover as banner for now -banner = siteConfig.banner.src; +banner = siteConfig.banner.src -const enableBanner = siteConfig.banner.enable; +const enableBanner = siteConfig.banner.enable -let pageTitle; +let pageTitle: string if (title) { - pageTitle = `${title} - ${siteConfig.title}`; + pageTitle = `${title} - ${siteConfig.title}` } else { - pageTitle = `${siteConfig.title} - ${siteConfig.subtitle}`; + pageTitle = `${siteConfig.title} - ${siteConfig.subtitle}` } -const favicons: Favicon[] = siteConfig.favicon.length > 0 ? siteConfig.favicon : defaultFavicons +const favicons: Favicon[] = + siteConfig.favicon.length > 0 ? siteConfig.favicon : defaultFavicons const siteLang = siteConfig.lang.replace('_', '-') - --- diff --git a/src/layouts/MainGridLayout.astro b/src/layouts/MainGridLayout.astro index 46b70d0..e3f9716 100644 --- a/src/layouts/MainGridLayout.astro +++ b/src/layouts/MainGridLayout.astro @@ -1,23 +1,21 @@ --- -import Layout from "./Layout.astro"; -import Navbar from "@components/Navbar.astro"; -import SideBar from "@components/widget/SideBar.astro"; -import Footer from "@components/Footer.astro"; -import BackToTop from "@components/control/BackToTop.astro"; +import Footer from '@components/Footer.astro' +import Navbar from '@components/Navbar.astro' +import BackToTop from '@components/control/BackToTop.astro' +import SideBar from '@components/widget/SideBar.astro' +import Layout from './Layout.astro' import { Icon } from 'astro-icon/components'; -import { siteConfig } from "../config"; +import { siteConfig } from '../config'; interface Props { - title?: string; - banner?: string; - description?: string; + title?: string + banner?: string + description?: string } const { title, banner, description } = Astro.props - const hasBannerCredit = siteConfig.banner.enable && siteConfig.banner.credit.enable const hasBannerLink = !!(siteConfig.banner.credit.url) - --- @@ -46,7 +44,8 @@ const hasBannerLink = !!(siteConfig.banner.credit.url)
-
+ +
diff --git a/src/pages/[...page].astro b/src/pages/[...page].astro index 0c540d9..9d0cbc2 100644 --- a/src/pages/[...page].astro +++ b/src/pages/[...page].astro @@ -1,21 +1,20 @@ --- -import MainGridLayout from "../layouts/MainGridLayout.astro"; -import Pagination from "../components/control/Pagination.astro"; -import {getSortedPosts} from "../utils/content-utils"; -import {PAGE_SIZE} from "../constants/constants"; -import PostPage from "../components/PostPage.astro"; -import {type GetStaticPaths} from "astro"; +import type { GetStaticPaths } from 'astro' +import PostPage from '../components/PostPage.astro' +import Pagination from '../components/control/Pagination.astro' +import { PAGE_SIZE } from '../constants/constants' +import MainGridLayout from '../layouts/MainGridLayout.astro' +import { getSortedPosts } from '../utils/content-utils' export const getStaticPaths = (async ({ paginate }) => { - const allBlogPosts = await getSortedPosts(); - return paginate(allBlogPosts, { pageSize: PAGE_SIZE }); + const allBlogPosts = await getSortedPosts() + return paginate(allBlogPosts, { pageSize: PAGE_SIZE }) }) satisfies GetStaticPaths // https://github.com/withastro/astro/issues/6507#issuecomment-1489916992 -const {page} = Astro.props; - -const len = page.data.length; +const { page } = Astro.props +const len = page.data.length --- diff --git a/src/pages/posts/[...slug].astro b/src/pages/posts/[...slug].astro index d167245..df9ca85 100644 --- a/src/pages/posts/[...slug].astro +++ b/src/pages/posts/[...slug].astro @@ -1,48 +1,48 @@ --- -import { getCollection } from 'astro:content'; -import MainGridLayout from "@layouts/MainGridLayout.astro"; -import ImageWrapper from "../../components/misc/ImageWrapper.astro"; -import {Icon} from "astro-icon/components"; -import PostMetadata from "../../components/PostMeta.astro"; -import {i18n} from "@i18n/translation"; -import I18nKey from "@i18n/i18nKey"; -import {getDir, getPostUrlBySlug} from "@utils/url-utils"; -import License from "@components/misc/License.astro"; -import {licenseConfig} from "src/config"; -import Markdown from "@components/misc/Markdown.astro"; -import path from "path"; -import {profileConfig} from "../../config"; -import {formatDateToYYYYMMDD} from "../../utils/date-utils"; +import path from 'node:path' +import { getCollection } from 'astro:content' +import License from '@components/misc/License.astro' +import Markdown from '@components/misc/Markdown.astro' +import I18nKey from '@i18n/i18nKey' +import { i18n } from '@i18n/translation' +import MainGridLayout from '@layouts/MainGridLayout.astro' +import { getDir, getPostUrlBySlug } from '@utils/url-utils' +import { Icon } from 'astro-icon/components' +import { licenseConfig } from 'src/config' +import PostMetadata from '../../components/PostMeta.astro' +import ImageWrapper from '../../components/misc/ImageWrapper.astro' +import { profileConfig } from '../../config' +import { formatDateToYYYYMMDD } from '../../utils/date-utils' export async function getStaticPaths() { - const blogEntries = await getCollection('posts', ({ data }) => { - return import.meta.env.PROD ? data.draft !== true : true; - }); - return blogEntries.map(entry => ({ - params: { slug: entry.slug }, props: { entry }, - })); + const blogEntries = await getCollection('posts', ({ data }) => { + return import.meta.env.PROD ? data.draft !== true : true + }) + return blogEntries.map(entry => ({ + params: { slug: entry.slug }, + props: { entry }, + })) } -const { entry } = Astro.props; -const { Content } = await entry.render(); +const { entry } = Astro.props +const { Content } = await entry.render() -const { remarkPluginFrontmatter } = await entry.render(); +const { remarkPluginFrontmatter } = await entry.render() const jsonLd = { - "@context": "https://schema.org", - "@type": "BlogPosting", - "headline": entry.data.title, - "description": entry.data.description || entry.data.title, - "keywords": entry.data.tags, - "author": { - "@type": "Person", - "name": profileConfig.name, - "url": Astro.site - }, - "datePublished": formatDateToYYYYMMDD(entry.data.published), - // TODO include cover image here + '@context': 'https://schema.org', + '@type': 'BlogPosting', + headline: entry.data.title, + description: entry.data.description || entry.data.title, + keywords: entry.data.tags, + author: { + '@type': 'Person', + name: profileConfig.name, + url: Astro.site, + }, + datePublished: formatDateToYYYYMMDD(entry.data.published), + // TODO include cover image here } - --- @@ -137,5 +137,61 @@ const jsonLd = { #post-container :nth-child(3) { animation-delay: calc(var(--content-delay) + 100ms) } #post-container :nth-child(4) { animation-delay: calc(var(--content-delay) + 175ms) } #post-container :nth-child(5) { animation-delay: calc(var(--content-delay) + 250ms) } -#post-container :nth-child(6) { animation-delay: calc(var(--content-delay) + 325ms) } - \ No newline at end of file +#post-container :nth-child(6) { animation-delay: calc(var(--content-delay) + 325ms) } + + + + + \ No newline at end of file