Commit 3fc1b18

HPCesia <me@hpcesia.com>
2025-01-23 08:53:07
refactor: image import
use ImageWrapper from Fuwari to improve image import.
1 parent 68cb97a
src/components/utils/ImageWrapper.astro
@@ -0,0 +1,59 @@
+---
+import { url } from '@utils/url-utils';
+import type { ImageMetadata } from 'astro';
+import { Image } from 'astro:assets';
+import path from 'path';
+interface Props {
+  id?: string;
+  src: string;
+  class?: string;
+  alt?: string;
+  position?: string;
+  basePath?: string;
+}
+
+const { id, src, alt, position = 'center', basePath = '/' } = Astro.props;
+const className = Astro.props.class;
+
+const isLocal = !(
+  src.startsWith('/') ||
+  src.startsWith('http') ||
+  src.startsWith('https') ||
+  src.startsWith('data:')
+);
+const isPublic = src.startsWith('/');
+
+let img;
+if (isLocal) {
+  const files = import.meta.glob<ImageMetadata>('../../**', {
+    import: 'default',
+  });
+  let normalizedPath = path.normalize(path.join('../../', basePath, src)).replace(/\\/g, '/');
+  const file = files[normalizedPath];
+  if (!file) {
+    console.error(
+      `\n[ERROR] Image file not found: ${normalizedPath.replace('../../', 'src/')}`
+    );
+  }
+  img = await file();
+}
+
+const imageClass = 'w-full h-full object-cover';
+const imageStyle = `object-position: ${position}`;
+---
+
+<div id={id} class:list={[className, 'relative overflow-hidden']}>
+  <div class="pointer-events-none absolute inset-0 bg-opacity-50 transition dark:bg-black/10">
+  </div>
+  {isLocal && img && <Image src={img} alt={alt || ''} class={imageClass} style={imageStyle} />}
+  {
+    !isLocal && (
+      <img
+        src={isPublic ? url(src) : src}
+        alt={alt || ''}
+        class={imageClass}
+        style={imageStyle}
+      />
+    )
+  }
+</div>
src/components/widgets/PostCardCover.astro
@@ -1,6 +1,6 @@
 ---
+import ImageWrapper from '@components/utils/ImageWrapper.astro';
 import { Icon } from 'astro-icon/components';
-import { Image } from 'astro:assets';
 
 interface Props {
   url: string;
@@ -15,7 +15,7 @@ const { url, title, cover } = Astro.props;
   <div>
     <Icon name="material-symbols:chevron-right-rounded" />
   </div>
-  <Image src={cover} alt={title} inferSize={true} />
+  <ImageWrapper src={cover} alt={title} />
 </a>
 
 <style>
src/components/widgets/ProfileCard.astro
@@ -1,17 +1,6 @@
 ---
 import { profileConfig } from '@/config';
-import avatarImg from '@assets/img/avatar.jpg';
-import { Image } from 'astro:assets';
-
-const avaterAttr = profileConfig.avatar
-  ? {
-      src: profileConfig.avatar,
-      alt: profileConfig.name,
-      inferSize: true,
-      width: 800,
-      height: 800,
-    }
-  : { src: avatarImg, alt: profileConfig.name };
+import ImageWrapper from '@components/utils/ImageWrapper.astro';
 ---
 
 <div
@@ -21,7 +10,11 @@ const avaterAttr = profileConfig.avatar
 >
   <div class="m-3 w-fit min-w-20">
     <a href="/about/">
-      <Image class="theme-border h-20 w-20 rounded-full border-4" {...avaterAttr} />
+      <ImageWrapper
+        class="theme-border h-20 w-20 rounded-full border-4"
+        src={profileConfig.avatar}
+        alt={profileConfig.name}
+      />
     </a>
   </div>
   <div class="mx-3 mb-5 flex w-full flex-col">
src/types/config.ts
@@ -10,7 +10,7 @@ export type SiteConfig = {
 };
 
 export type ProfileConfig = {
-  avatar?: string;
+  avatar: string;
   name: string;
   bio?: string;
   links: {
src/config.ts
@@ -17,7 +17,7 @@ export const siteConfig: SiteConfig = {
 };
 
 export const profileConfig: ProfileConfig = {
-  // avatar: 'https://example.com/avatar.png', // must be a absolute URL, if not set, will use src/asset/img/avatar.jpg
+  avatar: 'assets/img/avatar.jpg',
   name: 'John Doe',
   bio: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
   links: [],