Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions dev-server.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

> bsmhub@0.1.0 dev /app
> next dev
9 changes: 5 additions & 4 deletions generate-lighthouserc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { config } from 'dotenv';
import { getAllRoutes } from './src/app/sitemap.xml/sitemap';
import sitemap from './src/app/sitemap.xml/sitemap';

config({ path: '.env.local' });

Expand All @@ -15,13 +15,14 @@ async function generateConfig() {
console.log('🚀 Generating Lighthouse CI config...');

// 1. sitemap에서 동적으로 URL 경로를 가져옵니다.
const staticPaths = await getAllRoutes();
const sitemapData = await sitemap();
const urls = sitemapData.map((item) => item.url.replace('https://bsmhub.vercel.app', 'http://localhost:3000'));

// 2. Lighthouse CI 설정 객체를 만듭니다.
const config = {
ci: {
collect: {
url: staticPaths.map((path) => `http://localhost:3000${path}`),
url: urls,
startServerCommand: 'npm run start',
},
assert: {
Expand Down Expand Up @@ -50,4 +51,4 @@ async function generateConfig() {
}

// 스크립트 실행
generateConfig();
generateConfig();
24 changes: 24 additions & 0 deletions jules-scratch/verification/check_portfolio_console.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from playwright.sync_api import sync_playwright

def run(playwright):
browser = playwright.chromium.launch(headless=True)
context = browser.new_context()
page = context.new_page()

# Collect console messages
messages = []
page.on("console", lambda msg: messages.append(f"{msg.type}: {msg.text}"))

# Go to a portfolio page
page.goto("http://localhost:3000/portfolio/Minjae-Kwon")
page.wait_for_load_state("domcontentloaded")

# Print console messages
for msg in messages:
print(msg)

context.close()
browser.close()

with sync_playwright() as playwright:
run(playwright)
23 changes: 23 additions & 0 deletions jules-scratch/verification/find_bad_requests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from playwright.sync_api import sync_playwright

def run(playwright):
browser = playwright.chromium.launch(headless=True)
context = browser.new_context()
page = context.new_page()

def handle_response(response):
if response.status == 400:
print(f"Bad Request URL: {response.url}")
print(f"Request Method: {response.request.method}")
# print(f"Request Post Data: {response.request.post_data}")

page.on("response", handle_response)

# Go to a portfolio page
page.goto("http://localhost:3000/portfolio/Minjae-Kwon", wait_until="networkidle")

context.close()
browser.close()

with sync_playwright() as playwright:
run(playwright)
3 changes: 2 additions & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const nextConfig: NextConfig = {
'bsmhubsp.insert.team',
],
},
output: 'standalone',
// output: 'standalone',
productionBrowserSourceMaps: true,
};

export default nextConfig;
2 changes: 1 addition & 1 deletion src/app/components/layout/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const Tabs = ({ tabs }: TabsProps) => {
return (
<Link
key={mode}
className={`px-5 pb-2 border-b-2 ${
className={`flex items-center min-h-[48px] min-w-[48px] px-5 py-2 border-b-2 ${
isActive ? 'border-black' : 'border-transparent text-gray-base'
}`}
href={`?path=${mode}`}
Expand Down
1 change: 1 addition & 0 deletions src/app/components/modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useEffect } from 'react';
import { useModal } from './ModalContext';
import './modal.css';

export const Modal = () => {
const { isOpen, modalContent, closeModal } = useModal();
Expand Down
4 changes: 3 additions & 1 deletion src/app/components/modal/inputs/SingleInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ function Inputs({
`}
/>
{icon && iconMap[icon] && (
<button type="button">{iconMap[icon]}</button>
<button type="button" aria-label={icon}>
{iconMap[icon]}
</button>
)}
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/modal/inputs/SkillTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// import { IconX } from "@tabler/icons-react";
// import { useRef, useEffect } from "react";
// // import AutosizeInput from 'react-input-autosize';
// import './common/common.css';
import './common/common.css';

// type WriteProps = {
// mode: 'write';
Expand Down
6 changes: 5 additions & 1 deletion src/app/editor/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ export default function Editor() {
.catch((err) => console.error('Failed to load rich text editor:', err));
}, []);

return <div suppressHydrationWarning>{RichTextEditorComponent && <RichTextEditorComponent />}</div>;
return (
<div suppressHydrationWarning>
{RichTextEditorComponent && <RichTextEditorComponent aria-label="Rich Text Editor" />}
</div>
);
}
5 changes: 4 additions & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ body {
font-family: 'Threat';
font-style: normal;
font-weight: 400;
font-display: swap;
src:
local('Threat'),
url('https://fonts.cdnfonts.com/s/95719/Threat-2OAeX.woff') format('woff');
Expand All @@ -35,6 +36,7 @@ body {
font-family: 'Material Symbols Outlined';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/materialsymbolsoutlined/v215/kJF1BvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzByHX9rA6RzaxHMPdY43zj-jCxv3fzvRNU22ZXGJpEpjC_1v-p_4MrImHCIJIZrDCvHOejbd5zrDAt.woff2)
format('woff2');
}
Expand All @@ -59,6 +61,7 @@ body {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/materialicons/v142/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2)
format('woff2');
}
Expand Down Expand Up @@ -101,5 +104,5 @@ input[type="search"]::-webkit-search-results-decoration {
}

html {
font-size: 12px;
font-size: 16px;
}
2 changes: 0 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import Footer from './components/layout/Footer';
import './globals.css';
import './responsive.css';
import '@components/modal/inputs/common/common.css';
import '@components/modal/modal.css';
import Header from '@components/layout/Header';
import { ModalProvider, Modal } from '@components/modal';

Expand Down
36 changes: 4 additions & 32 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import { useEffect } from 'react';
// import Detail from '@components/detail/Detail';
import Buttons from '@components/modal/inputs/Buttons';
import Inputs from '@components/modal/inputs/SingleInput';
import PictureUpload from '@components/modal/inputs/PictureUpload';
import LabelInputs from '@components/modal/inputs/LabelOfInputs';
import InputListProvider from '@components/modal/inputs/InputListProvider';
import InputOfModal from '@components/modal/inputs/InputOfModal';
import dynamic from 'next/dynamic';
const InputOfModal = dynamic(
() => import('@components/modal/inputs/InputOfModal'),
);
import { FormConfig } from '@components/modal/inputs/types/inputTypes';
import { useModal } from '@components/modal';
import Checkbox from './components/modal/inputs/Checkbox';
Expand Down Expand Up @@ -104,33 +103,6 @@ export default function Home() {

return (
<div className="bg-white p-10">
{/* 기존 컴포넌트 테스트 */}
<div className="mb-10">
<h2 className="text-2xl mb-4">개별 컴포넌트 테스트</h2>
<LabelInputs label="이메일" required />
<Buttons />
<Inputs type="text" mode="write" />
<Inputs type="text" icon="search" />
<Inputs type="date" icon="calendar" />
<Inputs type="text" mode="read" value="읽기 전용 입력" />
<Inputs type="text" icon="check" />
<PictureUpload aspectRatio="4:3" />
<InputListProvider
config={{
inputs: [
{ type: 'date', width: 30, icon: 'calendar' },
{ type: 'text', width: 35, placeholder: '내용을 입력하세요' },
{ type: 'text', width: 35 },
],
}}
/>

<InputListProvider
config={{
inputs: [{ type: 'text', placeholder: '내용을 입력하세요' }],
}}
/>
</div>

{/* React Hook Form 통합 폼 */}
<div className="border-t-2 pt-10">
Expand Down
17 changes: 11 additions & 6 deletions src/app/portfolio/Portfolio.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Image from 'next/image';
import { Body, TitleEN } from '../components/system/text';

import Tabs from '../components/layout/Tabs';
Expand All @@ -23,12 +22,17 @@ const Portfolio = async ({ profileName, path = 'home' }: PortfolioProps) => {
const uuid = profile.profile_id;
const studentInfo = profile.profile_permission[0].student;

const profileDetail = await getProfileDetail(profileName);
const cooperationProjects = await getCooperationProjects(uuid);
const personalProjects = (await getPersonalProjects(uuid)).map((project) => ({
const [profileDetail, cooperationProjects, personalProjectsResult] =
await Promise.all([
getProfileDetail(profileName),
getCooperationProjects(uuid),
getPersonalProjects(uuid),
]);

const personalProjects = personalProjectsResult.map((project) => ({
...project,
authors: [
{ profileImage: convertFromDatabaseImageURL(profile.profile_image) }, // getPersonalProjects 함수에서 Join으로 가져오지 않은 개인 프로필 이미지 추가
{ profileImage: convertFromDatabaseImageURL(profile.profile_image) },
],
}));

Expand Down Expand Up @@ -58,12 +62,13 @@ const Portfolio = async ({ profileName, path = 'home' }: PortfolioProps) => {

return (
<div className="pt-[4.5rem] px-[2.75rem] relative">
<Image
<img
width={(120 / 16) * 14}
height={(120 / 16) * 14}
alt="프로필 사진"
src={convertFromDatabaseImageURL(profile.profile_image)}
className="rounded-sm absolute -top-20"
fetchPriority="high"
/>
<TitleEN className="mobile:mb-2">{profile.profile_name}</TitleEN>
<div className={`${containerCss} responsive-portfolioHome`}>
Expand Down
6 changes: 5 additions & 1 deletion src/app/portfolio/SearchTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import Link from 'next/link';
import { useState } from 'react';
import PortfolioCard from '../components/card/portfolio/PortfolioCard';
import dynamic from 'next/dynamic';
const PortfolioCard = dynamic(
() => import('../components/card/portfolio/PortfolioCard'),
);
import { PortfolioData } from './types';
import Inputs from '../components/modal/inputs/SingleInput';
import Checkbox from '../components/modal/inputs/Checkbox';
Expand Down Expand Up @@ -143,6 +146,7 @@ export default function SearchTab({
<Link
href={`/portfolio/${encodeURIComponent(data.profile.name)}`}
key={index}
prefetch={false}
>
<PortfolioCard profile={data.profile} projects={data.projects} />
</Link>
Expand Down
8 changes: 8 additions & 0 deletions src/app/portfolio/[profileName]/getPortfolioParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { getPersonalPortfolioData } from '@/services/server/portfolio/getPersonalPortfolioData';

export async function getPortfolioParams() {
const portfolioData = await getPersonalPortfolioData();
return portfolioData.map((data) => ({
profileName: encodeURIComponent(data.profile.name),
}));
}
5 changes: 5 additions & 0 deletions src/app/portfolio/[profileName]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import Portfolio from '../Portfolio';
import { getPortfolioParams } from './getPortfolioParams';

export async function generateStaticParams() {
return getPortfolioParams();
}

interface PortfolioProps {
params: Promise<{ profileName: string }>;
Expand Down
Loading
Loading