iT邦幫忙

2023 iThome 鐵人賽

DAY 14
0

設定網站的 UI

新增完專案後,就可以開始建立這個網站的 UI 了,首先要看這個網站有哪些功能,然後來決定需要哪些畫面,這個網站目前有以下幾個功能:

  • 選擇 QR Code 的類型
  • 輸入文字
  • 調整圖片大小
  • 調整圖片顏色

最後有一個產生 QR Code 的按鈕,按下去之後就會產生 QR Code,所以我們需要建立四個區塊,這些區塊就用 component 來處理。

所以我們就先在 app 資料夾下新增一個 components 資料夾,並且新增四個檔案:

$ mkdir app/components
$ touch app/components/SelectType.tsx app/components/TextInput.tsx app/components/SizeSlider.tsx app/components/ColorPicker.tsx

設定 State

在每個 component 中,都需要有一個 state 來儲存使用者的選擇,這裡我們先在 page.tsx 中使用 useState 來建立各個 component 的 state。

由於在 Next.js 版本 13 之後,在 app 資料夾下的每一個檔案預設都會是 Server Side Rendering(SSR),而在 SSR 中不能使用任何 React Hooks。如果要使用 React Hooks,就要在最前面加上 "use client"

// app/page.tsx
'use client'
import { useState, FormEvent } from 'react'
import { TextInput, SelectType, SizeSlider, ColorPicker } from './components'

export default function Home() {
  const [text, setText] = useState<string>('')
  const [qrType, setQrType] = useState<string>('URL')
  const [qrSize, setQrSize] = useState<number>(500)
  const [qrColor, setQrColor] = useState<string>('#000000')
  const [qrBgColor, setQrBgColor] = useState<string>('#ffffff')

  return (
  // 省略
  )
}

SelectType

第一個 component 是 SelectType,這個 component 是用來選擇 QR Code 的類型,這裡我們使用 select 來建立選項,並且使用從 page.tsx 的 props 來管理使用者的選擇,接下來的三個 component 也是一樣的做法。

// app/components/SelectType.tsx
import { FC, SetStateAction, Dispatch } from 'react'

interface SelectTypeProps {
  qrType: string
  setQrType: Dispatch<SetStateAction<string>>
}

const SelectType: FC<SelectTypeProps> = ({
  qrType,
  setQrType
}) => {
  return (
    <div className='mb-4'>
      <label className='block font-bold mb-2'>選擇 QR Code 類型</label>
      <select
        className='w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300'
        value={qrType}
        onChange={(e) => setQrType(e.target.value)}
      >
        <option value='URL'>URL</option>
        <option value='電話'>電話</option>
        <option value='地址'>地址</option>
        <option value='Email'>Email</option>
      </select>
    </div>
  )
}

export default SelectType

TextInput

第二個 component 是 TextInput,這個 component 是用來輸入文字,這裡我們使用 input 來建立輸入框。

import { FC, SetStateAction, Dispatch } from 'react'

interface TextInputProps {
  text: string
  setText: Dispatch<SetStateAction<string>>
}

const TextInput: FC<TextInputProps> = ({ text, setText }) => (
  <div className='mb-4'>
    <label className='block font-bold mb-2'>輸入文字</label>
    <input
      type='text'
      className='w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300'
      value={text}
      onChange={(e) => setText(e.target.value)}
    />
  </div>
)

export default TextInput

SizeSlider

第三個 component 是 SizeSlider,這個 component 是用來調整圖片大小,這裡我們使用 input 來建立輸入框,並且設定 type='range',這樣就可以使用滑動條來調整圖片大小。

import { FC, SetStateAction, Dispatch } from 'react'

interface SizeSliderProps {
  qrSize: number
  setQrSize: Dispatch<SetStateAction<number>>
}

const SizeSlider: FC<SizeSliderProps> = ({ qrSize, setQrSize }) => {
  return (
    <div className='mb-4'>
      <label className='block font-bold mb-2'>調整圖片大小</label>
      <input
        type='range'
        min='100'
        max='2000'
        value={qrSize}
        onChange={(e) => setQrSize(parseInt(e.target.value))}
      />
    </div>
  )
}

export default SizeSlider

ColorPicker

第四個 component 是 ColorPicker,這個 component 是用來調整圖片顏色,這裡我們使用 input 來建立輸入框,並且設定 type='color',這樣就可以使用顏色選擇器來調整圖片顏色。

import { FC, SetStateAction, Dispatch } from 'react'

interface ColorPickerProps {
  label: string
  color: string
  setColor: Dispatch<SetStateAction<string>>
}

const ColorPicker: FC<ColorPickerProps> = ({
  label,
  color,
  setColor
}) => {
  return (
    <div className='mb-4'>
      <label className='block font-bold mb-2'>{label}</label>
      <input
        type='color'
        value={color}
        onChange={(e) => setColor(e.target.value)}
      />
    </div>
  )
}

export default ColorPicker

整合 UI

最後我們就可以把這些 component 整合到 page.tsx 中,並且設定產生 QR Code 的按鈕。

import { TextInput, SelectType, SizeSlider, ColorPicker } from './components'

export default function Home() {
  // 省略

  const generateQRCode = (e: FormEvent) => {
    e.preventDefault()
    // 這裡是產生 QR code 的邏輯,之後再補上
  }

  return (
    <main className='flex min-h-screen flex-col items-center justify-between p-24'>
      <div className='container mx-auto p-4'>
        <h1 className='text-3xl mb-4'>QR Code 製造器</h1>
        <form onSubmit={generateQRCode} className='flex flex-col gap-y-5'>
          <SelectType qrType={qrType} setQrType={setQrType} />
          <TextInput text={text} setText={setText} />
          <div className='flex items-center justify-evenly'>
            <SizeSlider qrSize={qrSize} setQrSize={setQrSize} />
            <ColorPicker
              label='選擇顏色'
              color={qrColor}
              setColor={setQrColor}
            />
            <ColorPicker
              label='選擇背景顏色'
              color={qrBgColor}
              setColor={setQrBgColor}
            />
          </div>
          <div className='flex justify-center mt-5'>
            <button
              type='submit'
              className='bg-green-500 hover:bg-green-100 text-white hover:text-slate-700 font-bold py-2 px-4 rounded text-center'
            >
              產生 QR Code
            </button>
          </div>
        </form>
      </div>
    </main>
  )
}

最後的畫面如下:

20230923212422

今天的內容就到這邊,下一篇會試著跟後端 API 串接,並且產生 QR Code。


上一篇
Day 13 - Next.js 新專案,啟動!
下一篇
Day 15 - 解決 CORS 問題
系列文
30 天用 Rust 打造 QR Code 製造機30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言