樣式設計其實是這個練習中最簡單的部分。
步驟在不同框架中通常是相同的。
tailwindcss
實用類別 (utility classes) 取代自訂 CSS 類別npm install tailwindcss@latest @tailwindcss/vite@latest daisyui@latest
在 Vite 中添加 Tailwind CSS
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [tailwindcss(), ...other plugins...],
});
在專案中先安裝 daisyUI
插件
@import "tailwindcss";
@plugin "daisyui";
npm install daisyui@latest tailwindcss@latest @tailwindcss/postcss@latest postcss@latest --force
配置檔案
// .postcssrc.json
{
"plugins": {
"@tailwindcss/postcss": {}
}
}
在專案中先安裝 daisyUI
插件
// src/style.css
@import "tailwindcss";
@plugin "daisyui";
在 GithubProfileList
元件中,可以將 TailwindCSS 的類別 (class) 應用到標題(header)元素上,例如:
<div class="p-[0.75rem] col-span-full text-center">
<h1 class="text-3xl">Github Profile List (Angular Ver.)</h1>
</div>
header
的 CSS 類別可以從樣式表 (style sheet) 中移除,改為使用 Tailwind CSS 的類別 (class) 來設定樣式 (style)。
另外,可以利用 TailwindCSS 的類別 (class) 來設計 CSS Grid 佈局,簡化自訂 CSS。
在 App
元件的模板中
<div class="grid grid-cols-2 pt-0 pb-0 pl-[2rem] pr-[2rem]">
<GithubProfileList :usernames="usernames" />
</div>
// +layout.svelte
<div id="app" class="grid grid-cols-2 pt-0 pb-0 pl-[2rem] pr-[2rem]">
{@render children()}
</div>
在 AppComponent
中使用 @Component
裝飾器時,可以修改 styles
屬性。
為了在 CSS 類別 (class) 使用 @apply
,必須在配置中以 @reference
的方式包含 src/styles.css 檔案,確保不會重複包含該 CSS。
styles: `
@reference "../../../styles.css";
:host {
@apply grid grid-cols-2 pt-0 pb-0 pl-[2rem] pr-[2rem]
}
`,
Grid 佈局已成功應用於所有框架
CSS 樣式在範例中大致相同,但透過不同框架的控制流程語法 (control-flow syntax) 和資料插值語法 (interpolation),語法上會有所差異。
// GithubProfileCard.vue
<div class="card card-side bg-base-100 shadow-sm" v-if="profile">
<figure class="basis-[30%] grow shrink">
<img :src="profile.avatar_url" :alt="profile.name" />
</figure>
<div class="card-body basis-[70%] grow shrink">
<h2 class="card-title">{{ profile.login }}</h2>
<p>Name: {{ profile.name }}</p>
<p>Bio: {{ profile.bio || 'N/A' }}</p>
<p>Followers: {{ profile.followers }}</p>
<p>Following: {{ profile.following }}</p>
<p>Public Repos: {{ profile.public_repos }}</p>
<div class="card-actions justify-end">
<button class="btn btn-primary">
<a :href="profile.html_url" target="_blank" rel="noopener noreferrer">
<span class="text-white">View Profile</span>
</a>
</button>
</div>
</div>
</div>
<div v-else-if="error">Error: {{ error }}</div>
// github-profile-card.svelte
<div>
{#if profile}
<div class="card card-side bg-base-100 shadow-sm">
<figure class="basis-[30%] grow shrink">
<img src={profile.avatar_url} alt={profile.name} />
</figure>
<div class="card-body basis-[70%] grow shrink">
<h2 class="card-title">{ profile.login }</h2>
<p>Name: { profile.name }</p>
<p>Bio: { profile.bio || 'N/A' }</p>
<p>Followers: { profile.followers }</p>
<p>Following: { profile.following }</p>
<p>Public Repos: { profile.public_repos }</p>
<div class="card-actions justify-end">
<button class="btn btn-primary">
<a href={profile.html_url} target="_blank" rel="noopener noreferrer">
<span class="text-white">View Profile</span>
</a>
</button>
</div>
</div>
</div>
{:else if error}
<div>
<p>Error: {error}</p>
</div>
{/if}
</div>
@let status = profileResource.status();
@if (status === 'loading') {
<p>Loading profile...</p>
} @else if (status === 'error') {
<p>Error loading profile: {{ error() }}</p>
} @else {
@if (profile(); as profile) {
<div class="card card-side bg-base-100 shadow-sm" v-if="profile">
<figure class="basis-[30%] grow shrink">
<img [src]="profile.avatar_url" [alt]="profile.name" />
</figure>
<div class="card-body basis-[70%] grow shrink">
<h2 class="card-title">{{ profile.login }}</h2>
<p>Name: {{ profile.name }}</p>
<p>Bio: {{ profile.bio || 'N/A' }}</p>
<p>Followers: {{ profile.followers }}</p>
<p>Following: {{ profile.following }}</p>
<p>Public Repos: {{ profile.public_repos }}</p>
<div class="card-actions justify-end">
<button class="btn btn-primary">
<a [href]="profile.html_url" target="_blank" rel="noopener noreferrer">
<span class="text-white">View Profile</span>
</a>
</button>
</div>
</div>
</div>
} @else if (error()) {
@let message = error();
<div>Error: {{ message }}</div>
}
}