2020年12月12日
プログラミング
Blitz.jsとTailwind CSSでメモ帳アプリの作成【第2弾】
はじめに
新しい技術にチャレンジし続けるpalanのアドベントカレンダーDay12です!
昨日は「『えのすい七五三デジタルフォトフレーム』のデザイン作成フローについて」を書きました!
本記事では前回に引き続きBlitzjsとTailwind CSSでメモ帳アプリを作りたいと思います。
第2弾でやること
- メモのカテゴリーを作成
- seedファイルの作成
- サイドバーの作成
また,今回作成したコードの全体像はこちらになります。
メモのカテゴリーを作成
カテゴリーテーブルの作成
・category has_many memos
・category belongs_to user
という関係になるように,categoryテーブルを作成します。nameをカラムとして持つようにします。memoテーブルを作成したときと同様にblitz generate
コマンドで作成していきます。
$ blitz generate all category name:string memos:Memo\[] belongsTo:user
すると,schema.prismaに
model Category {
id Int @default(autoincrement()) @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
memos Memo[]
user User @relation(fields: [userId], references: [id])
userId Int
}
が追加されるので,
$ blitz db migrate
でDBに反映させます。
補足:blitz generateについて
ここで,blitz generate
について詳しく見てみましょう。https://blitzjs.com/docs/cli-generate にある通りblitz generate all
以外にもresource
やmodel
などあり,どこまで自動生成するか決められます。
また,has many, belongs toについてもドキュメントに書いてあり,
$ blitz g model project tasks:Task[]
$ blitz g model task belongsTo:project
という例が載っています。blitz g
はblitz generate
の省略形です。
今回はQueriesやPagesも作成したかったため,blitz g model
の代わりにblitz g all
を使いました。
メモテーブルにカテゴリーとの関連を追加
既にメモのPageやQueriesは存在しているので,今回はblitz g all
ではなくblitz g model
を使ってModelの変更のみ行います。
$ blitz g model memo belongsTo:category
schema.prismaのMemoにcategoryIdとcategoryが追加されました。
model Memo {
id Int @default(autoincrement()) @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
body String
user User @relation(fields: [userId], references: [id])
userId Int
}
↓
model Memo {
id Int @default(autoincrement()) @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
body String
user User @relation(fields: [userId], references: [id])
userId Int
category Category @relation(fields: [categoryId], references: [id])
categoryId Int
}
$ blitz db migrate
を忘れずに行ってください。
注意!!
既にメモテーブルにデータが入っている場合,migrationする際にcategoryIdが入っていない状態になるのでエラーが発生してしまいます。その場合, `$ blitz db reset` を実行してDBをリセットしてください。
CRUD機能
memoテーブルのときと一緒なので割愛させていただきます。 memoテーブルのCRUDは前回の記事 の「CRUD機能の実装」の章を参考にしてください。
以上でカテゴリーの完成です!🎉
カテゴリー作成の全体像はこちらのPRになります。
seedファイルの作成
スタイルを当てる前にデータを入れておきたいので,seedを作成しておきましょう。
ドキュメントに書いてある通り,db/seed.tsが最初から用意されているのでこちらに追記していきます。
userの作成
まずuserから作成していきます。既に存在するapp/auth/mutations/signup.tsのコードを参考に書いていきます。
const hashedPassword = await hashPassword("password!!")
const email = "hoge@example.com".toLowerCase()
const userId = (
await db.user.create({
data: { email, hashedPassword, role: "user" },
select: { id: true, name: true, email: true, role: true },
})
).id
categoryとmemoの作成
先程作成したuserのidを使います。 以下のように親と子のデータを同時に作成できます。
await db.category.create({
data: {
name: "カテゴリー1",
memos: {
create: [
{
title: "メモ1",
body:
"メモの1つ目です。",
user: { connect: { id: userId } },
},
{
title: "メモ2",
body:
"メモの2つ目です。",
user: { connect: { id: userId } },
},
],
},
user: { connect: { id: userId } },
},
})
DBに反映
$ blitz db seed
を実行したらDBに反映完了です🎉
変更されたコード全体はこちらのPRを参照してください。
Tailwind CSSとは
Tailwind CSSについてはアドベントカレンダーDay6の記事で分かりやすく説明しています。「Tailwind CSSとは」の箇所をぜひ読んでみてください!
Tailwind CSSの導入
$ blitz install tailwind
これだけで導入完了です!🎉
Recipeについて
Blitz.jsでは,Recipeというものがあります。Recipeを使うことでサードパーティー製のコードをたったひとつのコマンドで導入することができます。 GatsbyのRecipeにインスパイアされたみたいですね。
https://github.com/blitz-js/blitz/tree/canary/recipes にあるものは簡単に導入できます。Tailwind CSSの他にも
・chakra
・material-ui
・emotion
などがあります。chakraも最近話題になっていますね。
補足1:recipeができたのは2020年9月のこのPRで,それまでは手動で色々設定する必要がありました。
補足2:Tailwind CSSのv2がリリースされたのは2020年11月9日ですが,11月下旬にRecipeにも反映されました!(PR:https://github.com/blitz-js/blitz/pull/1486) 対応がとても早いですね✨
サイドバーの作成
サンプル
sidebarの例は公式にも載っていますが有料なので,今回はtailwindcomponentsというサイトの
https://tailwindcomponents.com/component/app-sidebar
を参考にしました。
デフォルトのスタイルの削除
まず,app/pages/index.tsxに書いてある
<style jsx global>{`
...
`}</style>
はデフォルトのstyleなので全て消しておきましょう。
asideとmainの構成をつくる
app/layouts/Layout.tsxが元々用意されているので,ここに書いてみましょう。
const Layout = ({ title, children }: LayoutProps) => {
return (
<>
<Head>
<title>{title || "memoApp"}</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="flex bg-gray-100 min-h-screen w-screen">
<aside className="bg-white w-60 h-screen sticky top-0">
<div className="flex items-center justify-center mt-10">
<a href="/">Application</a>
</div>
<nav className="mt-10">
<a
className="flex items-center py-2 px-8 bg-gray-200 text-gray-700 border-r-4 border-gray-700"
href="#"
>
ああああ
</a>
<a
className="flex items-center py-2 px-8 text-gray-600 border-r-4 border-white hover:bg-gray-100 hover:text-gray-700 hover:border-gray-700"
href="#"
>
いいいい
</a>
</nav>
</aside>
<main className="w-full">{children}</main>
</div>
</>
)
}
すると以下のようになります。
一部解説すると,
・bg-gray-100
のようにbg-
から始まるところはbackground colorです。
・mt
はmargin topの略です。mb
やmr
でbottomやrightにつけられる他,my
で上下,mx
で左右につけることができます。また,m
だけだと4方向につけられます。
・py
はpaddingで,marginと同様です。
・border-r
はborder-rightです。
・min-h-screenでmin-height: 100vhになります。
Sidebarコンポーネントの作成
app/layouts
のディレクトリにSidebar.tsxを作成します。
カテゴリー一覧を取得して表示するところまで実装すると以下のようになります。
import { useQuery, useRouter } from "blitz"
import getCategories from "app/categories/queries/getCategories"
import { useCurrentUser } from "app/hooks/useCurrentUser"
import { Category } from "@prisma/client"
const NavItem = ({ category, isActive }: { category: Category; isActive: boolean }) => {
const className = isActive
? "bg-gray-200 text-gray-700 border-r-4 border-gray-700"
: "text-gray-600 border-r-4 border-white hover:bg-gray-100 hover:text-gray-700 hover:border-gray-700"
return (
<a className={`flex items-center py-2 px-8 ${className}`} href={`/categories/${category.id}`}>
{category.name}
</a>
)
}
const Sidebar = () => {
const currentUser = useCurrentUser()
const router = useRouter()
const currentCategoryId = router.params.categoryId
const [{ categories }] = useQuery(getCategories, {
orderBy: { name: "asc" },
where: { userId: currentUser?.id },
})
return (
<aside className="bg-white w-60 h-screen sticky top-0">
<div className="flex items-center justify-center mt-10">
<a href="/">Application</a>
</div>
<nav className="mt-10">
{categories.map((category) => (
<NavItem
category={category}
isActive={Number(currentCategoryId) == category.id}
key={category.id}
/>
))}
</nav>
</aside>
)
}
export default Sidebar
また,app/layouts/Layout.tsxを以下のように変更します。
const Layout = ({ title, children }: LayoutProps) => {
return (
<>
...
<div className="flex bg-gray-100 min-h-screen w-screen">
<Suspense fallback="Loading...">
<Sidebar />
</Suspense>
<main className="w-full">{children}</main>
</div>
</>
)
}
これで完成です🎉
サイドバーをタップするとカテゴリーのページに飛ぶことができます。
POINT1
orderBy: { name: “asc” }とすることで,カテゴリーを名前順にならべています。
POINT2
router.params.categoryIdで/cartegories/[categoryId]のcategoryIdの部分を取得しています。その値を使ってsidebarの各カテゴリーがアクティブにするかどうかを判断しています。
変更されたコード全体はこちらのPRを参照してください。
まとめ
Tailwind CSSを使うことで,CSSを書かずに素敵なスタイルを当てることができました。
また,Reactの公式では
React doesn’t have opinions on how you put files into folders
と言及しているように「ディレクトリ構成をこうすべき」という方針は無いため,プロジェクト間の差異が大きく,ベストプラクティスがないというのがデメリットでした。一方,Blitz.jsでは元からLayoutのファイルがあったりseedのファイルが用意されていることで,「どのディレクトリに置こう」と悩むことなく進めることができ,誰が書いても同じようなディレクトリ構成にすることができるのではないでしょうか。
第3弾では引き続き他の画面にもスタイルを当てていきたいと思います。
Reactのお仕事に関するご相談
Bageleeの運営会社、palanではReactに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。
この記事は
参考になりましたか?
1
0
関連記事
2022年5月13日
Reactでオセロゲームを作る
2021年4月9日
Slack OAuth x React で Slack ユーザー認証を作ってみた!
2021年3月1日
Reactで使えるバリデーションライブラリを紹介!
2021年2月22日
Hasura Cloud × Auth0 × React でお手軽にTodoアプリを作ってみた!
2020年12月12日
Blitz.jsとTailwind CSSでメモ帳アプリの作成【第2弾】
2020年12月8日
コンポーネントを実装するときに意識すること
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへpalanでは一緒に働く仲間を募集しています
正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。
運営メンバー
Eishi Saito 総務
SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。
sasakki デザイナー
アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。
やまかわたかし デザイナー
フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。
Sayaka Osanai デザイナー
Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。
はらた エンジニア
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
こぼり ともろう エンジニア
サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。
ささい エンジニア
フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。
Damien
WebAR/VRの企画・開発をやっています。森に住んでいます。
ゲスト bagelee
かっきー
まりな
suzuki
miyagi
ogawa
雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。
いわもと
デザイナーをしています。 好きな食べ物はラーメンです。
taishi kobari
フロントエンドの開発を主に担当してます。Blitz.js好きです。
kubota shogo
サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!
nishi tomoya
aihara
グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。
nagao
SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。
Kainuma
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
sugimoto
asama
ando
iwasawa ayane
oshimo
異業界からやってきたデザイナー。 palanARのUIをメインに担当してます。 これからたくさん吸収していきます!