3
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.

【ひとりカレンダー】フロントエンド開発成長日記Advent Calendar 2022

Day 13

SvelteKit + Supabase Storageを使ってアイコン登録

Last updated at Posted at 2022-12-12

はじめに

Baas(Backend As A Service)で何かサービスを構築してみたいと思い、
firebaseを触ってみようと思ったところ、Firebase の代替と謳われているsupabaseを発見。

こちらの方が面白そうだと感じたため、構築してみることにしました。

今回はプロフィール画面を作成した際に、supabaseのstorage機能について触れたのでメモ。

使ったもの

  • Vite + SvelteKit + Typescript

    • @supabase/supabase-js
    • Flowbite-svelte
    • tailwind css
  • supabase

    • auth
    • db
    • storage

完成品

マイページ(アイコンアップロード前)

image.png

アップロード画面

image.png

マイページ(アイコンアップロード後)

image.png

実装方法

  1. Supabase管理画面より、storage > bucketを作成する
  2. Supabase管理画面から、profilesテーブルを作成する
  3. フロント側を整備する

1. Supabase管理画面より、storage > bucketを作成する

アイコンを保存するためのバケットを作成していきます。

  1. サイドメニューから、Storageを選択する
  2. 画面左上のNew bucketを選択し、任意のタイトルで保存をする。
    今回は公式のチュートリアル通りにavatarsとしました。

image.png

2. Supabase管理画面から、profilesテーブルを作成する

ユーザーに対してアイコンのURLを紐づけるためにprofilesテーブルを作成します。

  1. サイドメニューから、SQL Editorを選択する
  2. 画面左上のWelcomeを選択。
  3. Quick startの欄のUser Management Starterを選び、実行する
    (RUN or Ctrl + Enter)

image.png

3. フロント側を整備する

1と2でsupabase側の用意は完了なので、今度はフロント側を整備していく。

まずはファイルのアップロードフォームを作成する。

<script lang="ts">
  import { Label } from 'flowbite-svelte'
  let files: FileList
</script>

<div class="flex">
    <Label class="w-1/5 pb-2">アイコンアップロード</Label>
    <input
        class="w-4/5 text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
        type="file"
        accept="image/*"
        bind:value={files}
    />
</div>

こんな感じになりました。

image.png

次に、ファイルがアップロードされたら着火するイベントを作成する

<script lang="ts">
  let files: FileList

  const uploadIcon = async () => {
    if (!files || files.length === 0) {
      return
    }

    const file = files[0]
    const fileExt = file.name.split('.').pop()
    const filePath = `${session.user.id}/${Math.random()}.${fileExt}`

    await supabase.storage.from('avatars').upload(filePath, file)
  }
</script>

  <input
    class="w-4/5 block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
    type="file"
    accept="image/*"
    bind:files
    on:change={uploadIcon} // 追加
  />

sessionには現在のsession情報を格納しています。
avatar storageにユーザーごとのファイルを作成し、そこに画像を格納するようにしています。

次に、profilesテーブルに画像URLを保存します。

<script lang="ts">
  import { Label, Button } from 'flowbite-svelte'
  let files: FileList
  let url: string // 追加

  const updateUser = async () => {
    update_data = {
      id: $session.user.id,
      avatar_url: url
    }

    await supabase
      .from('profiles')
      .update(update_data)
  }

  const uploadIcon = async () => {
    if (!files || files.length === 0) {
      return
    }

    const file = files[0]
    const fileExt = file.name.split('.').pop()
    const filePath = `${session.user.id}/${Math.random()}.${fileExt}`

    await supabase.storage.from('avatars').upload(filePath, file)

    url = filePath // 追加
  }
</script>

<form class="w-full" on:submit|preventDefault="{updateUser}">
  // ------------------------------
  // 先ほどのファイルフォーム
  // ------------------------------
  <Button class="mt-10" type="submit" color="yellow" disabled={updating}>プロフィールを変更する</Button>
</form>

先ほど作ったuploadIconメソッドの最後にfilePathを変数に格納します。
また、formタグのサブミットイベントにupdateUserを定義し、サブミットボタンを押されたら着火するようにしました。

ニックネームや出身地など、一緒のフォームで入力できるようにすればプロフィール画面が作れますね

image.png

3
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
3
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?