Open6

tensura-app

ピン留めされたアイテム
cosugicosugi

今後やること

  • データベースとの連携
  • データの整理
  • 各用語(詳細画面)に固有のURLも割り当てる
  • 検索機能
  • フィルター機能
  • 認証機能
  • フッターの整形
  • ヒーローセクション
  • ロゴ(ホーム)ボタン
  • ハンバーガーメニューをshadcnのsheetを遣う(久々に30:00くらい)
  • [id]フォルダの作り方(久々に35:00くらい)
  • カードをホバーした時に影を強くする(transition、durationも忘れずに 久々に1:00:00くらい)
  • カードコンポーネントの作り方(型との紐付け、1:00:00くらい)
Hidden comment
cosugicosugi

GitHub Pages サイトを作成できない

Buildでエラーが出る。

エラー内容
Run npx --no-install next build
  npx --no-install next build
  shell: /usr/bin/bash -e {0}
  env:
    GITHUB_PAGES: true
⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry

  ▲ Next.js 14.2.5

   Creating an optimized production build ...
Failed to compile.

./utils/supabase/server.ts
Error: 
  x You're importing a component that needs next/headers. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/
  | react-essentials#server-components
  | 
  | 
   ,-[/home/runner/work/tensura-app/tensura-app/utils/supabase/server.ts:1:1]
 1 | import { createServerClient } from "@supabase/ssr";
 2 | import { cookies } from "next/headers";
   : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 3 | 
 4 | export const createClient = () => {
 5 |   const cookieStore = cookies();
   `----

Import trace for requested module:
./utils/supabase/server.ts
./components/itemList.tsx

./app/layout.tsx
Module not found: Can't resolve './clientLayout'

https://nextjs.org/docs/messages/module-not-found


> Build failed because of webpack errors
Error: Process completed with exit code 1.
GitHub Pagesの作り方
cosugicosugi

CardSectionにSupabaseのデータが反映されない

hook/useCardSection.ts
import { useState, useEffect } from "react";
import { createClient } from "@/utils/supabase/client";

interface ItemData {
  name: string;
  summary: string;
  category: string;
}

export const useCardSections = (categories: string[]) => {
  const [sections, setSections] = useState<{ [key: string]: ItemData[] }>({});
  const supabase = createClient();

  useEffect(() => {
    const fetchItems = async () => {
      const { data, error } = await supabase
        .from("items")
        .select("name, summary, category")
        .or("category.eq.character,category.eq.skills");

      if (error) {
        console.error("Error fetching items:", error);
        return;
      }

      console.log("Fetched data:", data); // データ取得の確認

      const groupedItems = data.reduce((acc, item) => {
        if (!acc[item.category]) {
          acc[item.category] = [];
        }
        acc[item.category].push(item);
        return acc;
      }, {} as { [key: string]: ItemData[] });

      console.log("Grouped items:", groupedItems); // グループ化されたデータの確認

      setSections(groupedItems);
    };

    fetchItems();
  }, []);

  return sections;
};
components/CardSection.tsx
import React from "react";
import { Card, CardContent } from "@/components/ui/card";
import {
  Carousel,
  CarouselContent,
  CarouselItem,
} from "@/components/ui/carousel";
import { cn } from "@/lib/utils";
import { useCardSections } from "../hook/useCardSections";

interface SectionConfig {
  category: string;
  title: string;
  allLink: string;
  color: string;
}

const cardSectionConfigs: SectionConfig[] = [
  {
    category: "character",
    title: "Characters",
    allLink: "/all-characters",
    color: "bg-blue-500",
  },
  {
    category: "skills",
    title: "Skills",
    allLink: "/all-skills",
    color: "bg-red-500",
  },
];

const CardSection: React.FC = () => {
  const sections = useCardSections(
    cardSectionConfigs.map((config) => config.category)
  );

  return (
    <div className="flex-grow p-4">
      {cardSectionConfigs.map((config, sectionIndex) => {
        const sectionItems = sections[config.category] || [];
        return (
          <section key={sectionIndex} className="my-6">
            <div className="flex justify-between items-center mb-3 px-3">
              <h2 className="text-xl font-bold">{config.title}</h2>
              <a href={config.allLink} className="text-sm">
                All {config.title}
              </a>
            </div>
            <Carousel
              opts={{
                align: "start",
              }}
              className="w-full"
            >
              <CarouselContent className="w-[93%] ml-[2px]">
                {sectionItems
                  .reduce<any[][]>((result, item, index) => {
                    if (index % 2 === 0) {
                      result.push([item]);
                    } else {
                      result[result.length - 1].push(item);
                    }
                    return result;
                  }, [])
                  .map((pair, pairIndex) => (
                    <CarouselItem key={pairIndex} className="basis-3/5 pl-2">
                      <div className="p-1">
                        {pair.map((item, itemIndex) => (
                          <Card key={itemIndex} className="mb-4">
                            <CardContent className="flex flex-col p-4 min-h-32">
                              <div className="flex items-center mb-2">
                                <div
                                  className={cn(
                                    "w-1 h-[18px] mr-2 inline-block",
                                    config.color
                                  )}
                                ></div>
                                <h3 className="text-lg font-semibold">
                                  {item.name}
                                </h3>
                              </div>
                              <p className="text-sm text-muted-foreground line-clamp-2">
                                {item.summary}
                              </p>
                            </CardContent>
                          </Card>
                        ))}
                      </div>
                    </CarouselItem>
                  ))}
              </CarouselContent>
            </Carousel>
          </section>
        );
      })}
    </div>
  );
};

export default CardSection;