はじめに
これの続きな?
以下実装
設計(再掲)
Style周りの環境構築
アプリ作っていく前にUIライブラリとcss-in-jsの導入する。
UIライブラリの選定
まぁデザイン力ないからね、こういうの使うほうが速い。
参考
いろいろあるもんだなぁ。
だけどなんかおしゃれなのあったーー!笑
これ、nextjsとの互換性強そう。
CSS-in-JSの選定
ライブラリ入れるにしても、その土壌がないとだめだわ。
これみてみる。
ピックアップするとこれらが気になる。
- Styled Component
- CSS Modules
- Styled JSX
- vanilla extract
- Stitches
- Emotion
どれを使おうかなと悩んだ。
悩んだ記事はこちら
結論は、Stitchesを使ってみようかな。 styled componentsを使おうかと思ったけど、なんかこっちのほうが新しいし、nextUIもこれ使ってるぽいからね。
Stitchesの導入
公式でnextjsに導入しているやつがあったからこれみてやろう
まずinstall
# uiレポジトリに導入 $ yarn workspace ui add @stitches/react # cdsアプリにも導入 $ yarn workspace cds add @stitches/react
次に、stiches.config.tsを作らないと行けないんだけど、たぶんこれ共通の設定をapps/cds
と apps/cdm
と packages/ui
にinstallしたいから、packagesにフォルダを作ろう。
$ mkdir packages/stitches-config $ cd packages/stitches-config $ yarn init yarn init v1.22.19 question name (stitches-config): question version (1.0.0): question description: package of stiches config files. question entry point (index.js): question repository url: question author: question license (MIT): question private: true success Saved package.json Done in 61.99s. $ cd ../../ $ yarn workspace stitches-config add @stitches/react
できて、編集を加えたファイルがこちら。
{ "name": "stitches-config", "version": "1.0.0", "description": "package of stiches config files.", "main": "index.ts", "private": true, "dependencies": { "@stitches/react": "^1.2.8" } }
じゃあstitches.config.ts
を作る。
import { createStitches } from '@stitches/react' export const { styled, getCssText } = createStitches({ theme: { fonts: { system: 'system-ui', }, colors: { hiContrast: 'hsl(206,10%,5%)', loContrast: 'white', }, fontSizes: { 1: '13px', 2: '15px', 3: '17px', }, }, })
とりあえずこれにする。 これを、index.tsでexportする。
export { styled, getCssText } from './stitches.config'
そしたらこれをui
のレポジトリで使う。
import * as React from "react" import { styled } from 'stitches-config' export const Button = styled('button', { fontFamily: '$system', color: '$hiContrast', variants: { size: { 1: { fontSize: '$1', }, 2: { fontSize: '$2', }, 3: { fontSize: '$3', }, }, }, })
使えてそーー! じゃあ、これをcdsレポジトリで使って表示してみる。
import { Button } from "ui" export default function View() { return ( <div> <p>this is cds</p> <Button size={3}>ボタン</Button> </div> ) }
あとSSRの設定もするみたい。 新たにpagesの下に_document.tsxを作っておく
import React from 'react' import NextDocument, { Html, Head, Main, NextScript } from 'next/document' import { getCssText } from 'stitches-config' export default class Document extends NextDocument { render() { return ( <Html lang="ja"> <Head> <style id="stitches" dangerouslySetInnerHTML={{ __html: getCssText() }} /> </Head> <body> <Main /> <NextScript /> </body> </Html> ) } }
さぁ表示!
完璧か?
NextUIの導入
次はこれの導入。結構わくわくしてる。
$ yarn workspace cds add @nextui-org/react
import React from 'react' + import NextDocument, { Html, Head, Main, NextScript, DocumentContext } from 'next/document' import { getCssText } from 'stitches-config' + import { CssBaseline } from "@nextui-org/react"; export default class Document extends NextDocument { + static async getInitialProps(ctx: DocumentContext) { + const initialProps = await NextDocument.getInitialProps(ctx) + return { + ...initialProps, + styles: React.Children.toArray(initialProps.styles), + } ; } render() { return ( <Html lang="ja"> <Head> + {CssBaseline.flush()} <style id="stitches" dangerouslySetInnerHTML={{ __html: getCssText() }} /> </Head> <body> <Main /> <NextScript /> </body> </Html> ) } }
Providerの設置。
import { NextUIProvider } from '@nextui-org/react' import type { AppProps } from "next/app"; export default function MyApp({ Component, pageProps }: AppProps) { return ( <NextUIProvider> <Component {...pageProps} /> </NextUIProvider> ) }
これで準備ができた。 じゃあやってみるべ!!
- import { Button } from "ui" + import { Button } from "@nextui-org/react"; export default function View() { return ( <div> <p>this is cds</p> - <Button size={3}>ボタン</Button> + <Button color="gradient" auto shadow>いい感じのボタン</Button> </div> ) }
えーーー、、きれぇーーー。。ww
準備オーケー
CDS作成
じゃあついにCDS作っていくか。
一覧画面
ホームページの一覧画面から。コンセプトは「イメージで感じ取るブログ」。本屋の背表紙で買うような感じで。
Cardコンポーネント
まずはCard作るべ。 そのためにuiにNextUIいれる。
あと、このプロジェクトの日付管理はdate-fnsにしよ。cdateも気になるけども。
$ yarn workspace ui add @nextui-org/react date-fns $ yarn workspace cds add date-fns
これで、アプリ側から呼ぶとエラーが。
エラー内容と解決策はこれ。
なんか他のレポジトリからimportするときはこの設定が必要っぽい...?ほんとか?
まぁけどこれは入れた。
module.exports = { experimental: { externalDir: true, }, }
いい感じに表示されてきた。
headerコンポーネント
とりあえずHeaderコンポーネントを作った。
これを全ページで適用したい。どうやら、Layoutというものを定義したほうが良いらしい。
nextjs-ja-translation-docs.vercel.app
なので作ってみた。
import { ReactNode } from 'react'; import { Header } from 'ui' type Props = { children: ReactNode } export const Layout = ({ children }: Props) => { return ( <> <Header /> <main> {children} </main> </> ); }
んでどうやら子要素に指定するのはReactNode
とReactElement
があるが、用途が違うらしい。
- ReactNode : まじで何でもいい。
- ReactElement : 一個の要素をよこせ。
んで、作ったLayoutを_app.tsx
に配置
import { NextUIProvider, useSSR } from '@nextui-org/react' import type { AppProps } from "next/app"; + import { Layout } from '../components/Layout'; export default function MyApp({ Component, pageProps }: AppProps) { const { isBrowser } = useSSR() return ( isBrowser && ( <NextUIProvider> + <Layout> <Component {...pageProps} /> + </Layout> </NextUIProvider> ) ) }
これでいい感じに表示された。
footerの作成
NextUIにfooterがなかったから、stitchesで作った。
とりあえずこんな感じ。
NextUIはthemeも提供していてありがたいなぁ。
デザイナーさんがやるところを全部やってくれる。
これをそのまんまLayoutの一番下にやると、こんな感じに。
みたらわかるようにFooterが上になっちゃう。
Layoutを変えて、コンテンツが画面高さよりも少ない場合も最下部にいくようにしよう
flexを使って最下部に持っていった。
完成したのはこんな感じ。
これやりながらわかったんだけど、Stitchesってすごい可変的な引数のとり方( 例:width: $propsWidth ) できないっぽい?マジ?
まぁやらないほうがいいのはわかるし、思想も理解できるけど、ここまでの制限があると後々少し嫌になりそう。
style整え
いろいろstyleを整えて、最終調整
完成したらこんな感じになった。
詳細ページの作成
次は詳細ページを作っていこう。
どんなブログがいいだろうか。「本屋を背表紙で買った人はおそらく作者に興味がない」という想像から、作者情報は文末にしよう。
けど目次は横がいい!(個人的欲求)
あともしできるんだったら、ブログを進んでいくごとに夕焼けになるようにしたい。(なんか思いつき)
...かな?とりあえずここまで作ってみよう。
ページの枠の作成
とりあえずページの枠を作成しよう。
routingはこれを参考に。
nextjs-ja-translation-docs.vercel.app
これでfile作成
import { Text } from "@nextui-org/react"; export default function View() { return ( <Text>詳細ページです</Text> ) }
よし、表示もできるっぽい
ざっくりとレイアウト作成
そういえば、「何かを囲う時のclassの接尾字の命名規則」をchatGPTに作ってもらったので記載。
Q. 何かを囲う時は、class名の末尾に何を使うのが適切? A. 何かを囲む要素の場合、一般的には以下のような接尾辞がclass名に使われることが多いです。 1. -wrapper(ラッパー) - 例: content-wrapper 2. -container(コンテナ) - 例: header-container 3. -box(ボックス) - 例: search-box 4. -area(エリア) - 例: footer-area 5. -section(セクション) - 例: banner-section ただし、命名規則はプロジェクトやチームによって異なる場合があるため、一貫性を保つためにコーディング規約やガイドラインを設定することが推奨されます。このような規約やガイドラインに従ってclass名を選択することが適切です。引用元:ChatGPT
Q. じゃあいま出した5つのうち、最初の3つだけの使用規則を作ってください。 A. 以下に、1-3の接尾辞を使った改訂された命名規則の使用例を示します。 1. -wrapper(ラッパー) 使用例: content-wrapper, image-wrapper 使用目的: 他の要素を包み、レイアウトやスタイリングの目的で使用される。余白やサイズ調整などのスタイルを適用する場合に適している。 2. -container(コンテナ) 使用例: header-container, form-container 使用目的: 関連する要素をグループ化し、共通のスタイリングやレイアウトを適用する。親要素に対してグリッドシステムやフレックスボックスを適用する場合に適している。 3. -box(ボックス) 使用例: search-box, info-box 使用目的: 独立した機能を持つコンポーネントを表現する。そのコンポーネント内で独自のスタイリングやレイアウトが必要な場合に適している。 これらの命名規則は、一貫性を保つためにプロジェクトやチームで共有されるべきです。また、プロジェクトに応じてカスタマイズされることがあります。引用元:ChatGPT
あとこれめっちゃめちゃ参考になった。
いやーけど、style関数できないのきつくないかい?選択肢でしかpropsを与えられないのは辛い。imageUrlとか与えたいもん。
無理なのでcssで与えるようにしました。
こんな感じで設定しました。
表示したらこんな感じ。
リファクタリング
ちょっと立ち止まってリファクタリング。
Styleコンポーネントからcss propsに。
どうやらStitchesはcss propsも使えるらしい。
そっちがいいので変更。
だけどなんかStyledコンポーネントにしたほうが良さげなものと、CssPropsのほうが良さげのものがあるな。
たぶんこんな感じ。
- Styledコンポーネント:そのタグ自体に意味がある場合
- 例:FooterContainer, FooterContent
- CssProps:そのタグ自体に意味がない場合
- 例:余白を付けたいがためのStyleなど
prettierの設定
開発していてやりづらい!!
自動で自分の間違いを修正してほしい。
ということで環境作りから。
$ mkdir packages/prettier-config-custom $ cd packages/prettier-config-custom/ $ yarn init yarn init v1.22.19 question name (prettier-config-custom): question version (1.0.0): question description: package of prettier config files. question entry point (index.js): question repository url: question author: question license (MIT): question private: true success Saved package.json Done in 32.38s. $ cd ../.. $ yarn workspace prettier-config-custom add -D prettier
んで、ファイルも生成。こちらを参考。
module.exports = { printWidth: 100, tabWidth: 2, useTabs: false, semi: false, singleQuote: true, quoteProps: "as-needed", jsxSingleQuote: false, trailingComma: "es5", bracketSpacing: true, bracketSameLine: false, proseWrap: "always", endOfLine: "lf", embeddedLanguageFormatting: "off", }
じゃあこれをappsとuiに導入する。
まず諸々のinstallから。
$ yarn workspace cds add -D prettier eslint-config-prettier $ yarn workspace ui add -D prettier eslint-config-prettier
突然だけど...
一旦ここまで!!これはWIPにします。