1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Astro・shadcn/ui・Newtでポートフォリオサイトを作った手順メモ

Posted at

Astro(静的サイトジェネレーター)を使ってポートフォリオサイトを作って見たので、その時の手順などを簡単にまとめました。
コンテンツの部分はNewt、UIフレームワークはshadcn/ui、デプロイはCloudflarePagesを使っています。

Astroをインストール

まずはAstroをインストールします。

npm create astro@latest
#or
bunx create-astro@latest
#or
pnpm create astro@latest
- Where should we create your new project?
./your-app-name
- How would you like to start your new project?
Choose a starter template (or Empty)
- Install dependencies?
Yes
- Do you plan to write TypeScript?
Yes
- How strict should TypeScript be?
Strict
- Initialize a new git repository? (optional)
Yes/No

インストール時に初期設定を行います。

astro1.png

インストールが完了すると上記のディレクトリ構造が作られます。

astro dir.png

ページやコンポーネントの配置などはNext.jsなどと似ています。
pagesディレクトリにファイルを増やしていくことで、自動的にルーティングを行ってくれます。
ファイル名を404とすると、自動的に404のエラー用のページになります。
動的なページは[id]のように[]で囲む必要があります。

Reactコンポーネントを使えるようにする

AstroではReact、Vue、Svelteなど有名なフロントエンドフレームワークをサポートしています。
今回はReactを使用できるようにします。

npx astro add react
astro.config.mjs
import { defineConfig } from 'astro/config';

import react from "@astrojs/react";

// https://astro.build/config
export default defineConfig({
  integrations: [react()]
});

Tailwindとshadcn/uiをインストール

UIフレームワークはTailwindとshadcn/uiを使用します。

npx astro add tailwind
astro.config.mjs
import { defineConfig } from 'astro/config';
import react from "@astrojs/react";

import tailwind from "@astrojs/tailwind";

// https://astro.build/config
export default defineConfig({
  integrations: [react(), tailwind()]
});
npx shadcn-ui@latest init
Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › ./src/styles/globals.css
Do you want to use CSS variables for colors? › no / yes
Where is your tailwind.config.js located? › tailwind.config.mjs
Configure the import alias for components: › @/components
Configure the import alias for utils: › @/lib/utils
Are you using React Server Components? › no

astro.config.mjstailwind.config.mjsでtailwindの設定をしていきます。

astro.config.mjs
export default defineConfig({
  integrations: [
    react(),
    tailwind({
      applyBaseStyles: false
    })
  ]
})
tailwind.config.mjs
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],

Layout.astro
---
import '@/styles/globals.css'

interface Props {
  title: string
}

const { title } = Astro.props
---

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="description" content="Astro description" />
    <meta name="viewport" content="width=device-width" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="generator" content={Astro.generator} />
    <title>{title}</title>
  </head>
  <body>
    <slot />
  </body>
</html>

Layoutファイルでtailwindのglobals.cssを読み込みます。

shadcn/uiでは使用したいコンポーネントを個別にインストールして使用していきます。

bunx shadcn-ui@latest add button 
import { Button } from '@/components/ui/button'
<Button variant="outline"/>

Newtと連携する

まずはNewtにコンテンツを入れていきます。

astro5.png

コンテンツを入れたらAstroとNewtを連携させます。

npm install newt-client-js
#or
pnpm add newt-client-js
#or
bun add newt-client-js
env
NEWT_SPACE_UID=your-space-id
NEWT_CDN_API_TOKEN=xxxxxxxxxxxxxxx
env.d.ts
interface ImportMetaEnv {
  readonly NEWT_SPACE_UID: string
  readonly NEWT_CDN_API_TOKEN: string
}

env.d.tsでImportMetaEnvを設定すると環境変数の自動補完が効くようになります。

newt-client
import { createClient } from 'newt-client-js'

export const newtClient = createClient({
  spaceUid: import.meta.env.NEWT_SPACE_UID,
  token: import.meta.env.NEWT_CDN_API_TOKEN,
  apiType: 'cdn'
})

一覧取得

import { newtClient } from '@/lib/newt-client'

export const getBlogs = async () => {
  const { items: blogs } = await newtClient.getContents({
    appUid: 'blog',
    modelUid: 'blog',
    query: {
      select: ['title', 'slug', 'body'],
      order: ['_sys.createdAt']
    }
  })
  return blogs
}

queryに条件を指定することが可能です。

詳細取得

/blog/[id].astro
---
export const getStaticPaths = async () => {
  const { items: blogs } = await newtClient.getContents<Blog>({
    appUid: 'blog',
    modelUid: 'blog',
    query: {
      select: ['title', 'slug', 'body'],
    },
  })
  return blogs.map((blog) => ({
    params: { id: blog.slug },
    props: { blog }
  }))
}

const { blog } = Astro.props
---

<Layout>
  <div>{blog.title}</div>
  <div>{blog.body}</div>
</Layout>

ページネーションもできる

Astroのpaginateを使えばページネーションも実装できます。

/blog/[id].astro
---
import { newtClient } from '@/lib/newt-client'
import type { GetStaticPathsOptions } from 'astro'

export const getStaticPaths = async ({ paginate }: GetStaticPathsOptions) => {
  const { items: blogs } = await newtClient.getContents<Blog>({
    appUid: 'blog',
    modelUid: 'blog',
    query: {}
  })
  return paginate(blogs, { pageSize: 1 }) // 1ページに表示する個数
}

const { page } = Astro.props

propsのpageには下記のページネーションの情報が入っています。

currentPage: 1,
lastPage: 4,
url: { current: '/case/1', next: '/case/2', prev: undefined 

astro pagination.png

shadcn/uiのPaginationコンポーネントで簡単にページネーションのUIを実装できます。

下記は実装例です。

 pagination
import {
  Pagination,
  PaginationContent,
  PaginationEllipsis,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious
} from '@/components/ui/pagination'

type Props = {
  total: number
  currentPage: number
  url: {
    current: string | undefined
    next: string | undefined
    prev: string | undefined
  }
}

const Pagination = ({ total, currentPage, url }: Props) => {
  return (
    <Pagination>
      <PaginationContent>
        <PaginationItem hidden={!url.prev}>
          <PaginationPrevious href={url.prev} />
        </PaginationItem>
        <PaginationItem hidden={!url.prev}>
          <PaginationLink href={url.prev}>{currentPage - 1}</PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationLink isActive>{currentPage}</PaginationLink>
        </PaginationItem>
        <PaginationItem hidden={!url.next}>
          <PaginationLink href={url.next}>{currentPage + 1}</PaginationLink>
        </PaginationItem>
        <PaginationItem hidden={currentPage + 1 >= total}>
          <PaginationEllipsis />
        </PaginationItem>
        <PaginationItem hidden={!url.next}>
          <PaginationNext href={url.next} />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  )
}

export default Pagination

Astroのデプロイ

AstroのデプロイはVercel・Cloudflare Pages・GitHub Pagesなどのホスティングサービスを使えば簡単にできます。
ドキュメントにホスティングサービスごとのデプロイ方法が記載されています。

CloudflarePages

cloud fire.png

今回はCloudflarePagesでデプロイしました。

cloud fire env.png

Newtの環境変数は別途設定する必要があります。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?