Astroでギャラリー
作成:
はじめに
以前からギャラリーは別サーバーの PHP で設置していた。
これを Astro で実現できないかと考えてはいたが Astro 自体よくわかっていなかったの
でそれができずにいた。
テスト用ページは以下
ギャラリー
画像一覧ページです
https://ubanis.com/oldgallery
ギャラリーを作る
readdirSync
がとっても重要だが他のサイトで解説されてるので特に書かない。
ギャラリーの画像の構造
元々のギャラリーは画像のタイプフォルダ以下に年数のフォルダが入った構造になってい る。
├── junk
│ ├── 2016
│ │ ├── 2016-1211-01.jpg
│ │ ├── 2016-1211-02.jpg
とりあえずこれに合わせて作ることにした。以下スタイルシートは割愛。
ファイル操作関数
src/utils/fileUtil.ts
import * as fs from "fs";
import * as path from "path";
export function getDirectories(dirPath: string) {
return fs.readdirSync(dirPath).filter(function (file) {
return fs.statSync(dirPath + "/" + file).isDirectory();
});
}
export function getImageFiles(dirPath: string) {
const imageType = [".gif", ".png", ".jpeg", ".jpg", ".webp", ".avif"];
const files = fs
.readdirSync(dirPath, { withFileTypes: true })
.filter(dirent => dirent.isFile())
.map(({ name }) => name)
.filter(function (file) {
return imageType.includes(path.extname(file).toLowerCase());
});
return files;
}
ギャラリーリスト
ギャラリーのリスト用コンポーネント
src/components/GalleryList.astro
---
import { IMAGE_LOCAL_DIR, GALLERY_DIR } from '@config/config';
import { getDirectories } from '@utils/fileUtil.ts';
import Block from './Block.astro';
interface GalleryDirList {
[key:string]:string[]
};
const galleryList :GalleryDirList ={};
const imageTypeDir = (() => {
try {
return getDirectories(IMAGE_LOCAL_DIR);
}
catch(e) {
console.log(e)
return [];
}
})();
for(const t of imageTypeDir)
{
galleryList[t] = getDirectories(IMAGE_LOCAL_DIR + t);
}
---
<Block>
{imageTypeDir?.map((type) => (
<input type="checkbox" name="imagelist" id={type} class="toggle" />
<label for={type} class="Label">{type}</label>
<ul class="content">
{galleryList[type]?.map((year) => {
return (
<li><a href=`${GALLERY_DIR}/${type}/${year}`>{year}</a></li>
);
})}
</ul>
))}
</Block>
IMAGE_LOCAL_DIR
はローカル上でのギャラリー用フォルダへのパス (public/upload/img/
)GALLERY_DIR
はサイト上のギャラリーページへの URL(/gallery
)imageTypeDir
にギャラリーフォルダからタイプ別フォルダ一覧の名前を読み込むgalleryList[タイプ名]
にタイプ名フォルダ以下のフォルダを読み込む- タイプ名フォルダの数だけリストを生成する。
ギャラリーのインデックスページ
単純にギャラリーリストが表示されるだけのページ。
---
import BaseLayout from "@layouts/BaseLayout.astro";
import GalleryList from "@components/GalleryList.astro";
---
<BaseLayout pageTitle="ギャラリー" description="画像一覧ページです">
<div class="parent">
<div style="align-self:start">
<GalleryList />
</div>
<div>
<p>メニューから選ぶと、ここに画像一覧が表示されます。</p>
</div>
</div>
</BaseLayout>
ギャラリー画像表示ページ
先程のリストを左側に表示し、右側に画像一覧を表示して画像を閲覧するページ
src/pages/gallery/[type]/[year].astro
---
import BaseLayout from "@layouts/BaseLayout.astro";
import GalleryList from "@components/GalleryList.astro";
import MyImage from "@components/MyImage.astro";
import { IMAGE_LOCAL_DIR, IMAGE_WEB_DIR } from "@config/config";
import { getDirectories, getImageFiles } from "@utils/fileUtil";
export function getStaticPaths() {
interface Params {
[param: string]: {
[str: string]: string;
};
}
const paths: Params[] = [];
const imageTypeDir = (() => {
try {
return getDirectories(IMAGE_LOCAL_DIR);
} catch (e) {
console.log(e);
return [];
}
})();
for (const t of imageTypeDir) {
const years = getDirectories(IMAGE_LOCAL_DIR + t);
for (const y of years) {
paths.push({ params: { type: t, year: y } });
}
}
return paths;
}
const { type, year } = Astro.params;
const thumbnailSize = "128px";
const title = type + " " + year;
const imageWebPath = IMAGE_WEB_DIR + type + "/" + year + "/";
const dirLocalPath = "public" + imageWebPath;
const imageSrc: string[] = [];
const imageFiles = (() => {
try {
return getImageFiles(dirLocalPath);
} catch (e) {
console.log(e);
return [""];
}
})();
imageFiles.reverse();
for (const s of imageFiles) {
imageSrc.push(imageWebPath + s);
}
---
<BaseLayout pageTitle={title} description="画像一覧ページです">
<link rel="stylesheet" href="/fancybox/fancybox.css" />
<div class="parent">
<div style="align-self:start">
<GalleryList />
</div>
<div>
<h1>{type}</h1>
<h2>{year}</h2>
<ul>
{
imageSrc?.map((f) => (
<li>
<a data-fancybox="group" href={f}>
<MyImage
src={f}
width={thumbnailSize}
height={thumbnailSize}
alt={f}
/>
</a>
</li>
))
}
</ul>
</div>
</div>
<script is:inline src="/fancybox/fancybox.umd.js"></script>
</BaseLayout>
IMAGE_WEB_DIR
はウェブ上のギャラリー画像用フォルダへの URL(/upload/img/
)- getStaticPaths でタイプの数だけ年別フォルダのパスを作る(for の二段重ねなので多 分もっと賢いやり方があるはず)
- タイプ名と年からギャラリー用画像フォルダ以下から拡張子でフィルタリングした画像 のリストを取得する
- あとはその数だけサムネイルとともにリンクを作成する
最後に
最初律儀に getstaticPaths ですべてのパスの配列を手書きしたり json にしてみたり無
駄なことをしていた。for でreaddirSync
でいいじゃんということに気づいた結果がこ
れ。
フォルダツリーすべてをギャラリーにできない上にルートフォルダの画像も表示しない限 定仕様なのでここでしか使えない感じではある。多分正しく賢いやり方があると思うが今 日はここまで。
(ちなみに元ギャラリーの画像は 2000 枚以上あるのでここに置くわけにもいかずここ のギャラリーはブログ用に使うことにします)