Skip to content

Conversation

@hamo-o
Copy link
Contributor

@hamo-o hamo-o commented Feb 6, 2025

#️⃣ 연관된 이슈>

📝 작업 내용> 이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지 첨부 가능)

  • 루트로 진입하면 랜딩페이지로 리다이렉트합니다.
  • 랜딩페이지를 마크업합니다.
image

🙏 여기는 꼭 봐주세요! > 리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

  • 이미지 사이즈가 작은 webp 확장자로 변환하고, 반응형에 대응하는 이미지를 만들어주는 스크립트를 작성했습니다. (거기에 필요한 sharp 패키지 devDependencies로 설치했습니다.)
  • 반응형까지 챙기지는 않더라도, 이미지를 저희가 직접 넣어줘야 하는 상황에는 적어도 webp로의 변환 꼭 부탁드려요~! (저는 처음에 안깨지게 하려고 4배로 뽑았다가 깃에 올라가지도 않음..)

Summary by CodeRabbit

  • New Features
    • Launched an updated landing page experience with modern design, including dedicated visual elements and responsive image support that improves load performance.
    • Introduced a new image optimization tool to automatically enhance image delivery.
    • Added a Google icon component to streamline authentication options.
    • Updated navigation to redirect users from the home route to the new landing page.
  • Refactor
    • Refined UI component implementations for improved consistency without altering user-facing functionality.

@hamo-o hamo-o added the 🖥️ FE Frontend label Feb 6, 2025
@hamo-o hamo-o added this to the 2차 스프린트 milestone Feb 6, 2025
@hamo-o hamo-o self-assigned this Feb 6, 2025
@hamo-o hamo-o requested a review from dioo1461 as a code owner February 6, 2025 10:12
@coderabbitai
Copy link

coderabbitai bot commented Feb 6, 2025

Walkthrough

This pull request introduces several enhancements across the frontend. It updates the routing system by adding a new landing page route and associated components and styles, while removing an outdated lazy-loaded home route. New UI components, including a Google icon and a responsive image component, are added. A minor update to the Button component reorders arguments for class names. A new script using the "sharp" library automates image conversion and optimization, with related changes added to package.json.

Changes

File(s) Change Summary
frontend/package.json Added new script "optimize-image": "node src/scripts/optimize-image.cjs" and devDependency "sharp": "^0.33.5".
frontend/src/components/Button/index.tsx, frontend/src/components/Icon/component/Google.tsx, frontend/src/components/Icon/index.ts, frontend/src/components/Image/index.tsx Button: Reordered arguments for clsx.
Google Icon: Added new component with default props and display name.
Icon Export: Updated export to include Google.
Image: Added new component with responsive image handling and ImageProps interface.
frontend/src/routeTree.gen.ts, frontend/src/routes/index.lazy.tsx (deleted), frontend/src/routes/index.tsx, frontend/src/routes/landing/index.tsx, frontend/src/routes/landing/@components/index.tsx, frontend/src/routes/landing/@components/LandingImages.tsx, frontend/src/routes/landing/@components/index.css.ts Updated routing definitions:
- Modified route imports and renamed index lazy route to direct index route with redirection to landing.
- Introduced new landing route and components with corresponding style definitions.
frontend/src/scripts/optimize-image.cjs Added a new script to convert images to WebP format using the sharp library, including breakpoint resizing and deletion of original files.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant R as Root Route ("/")
    participant L as Landing Route ("/landing")
    U->>R: Access "/"
    R->>R: Trigger beforeLoad hook
    R->>L: Redirect to "/landing"
    L-->>U: Render Landing page
Loading

Assessment against linked issues

Objective Addressed Explanation
Image Optimization (#71)
Landing Page Routing and Markup (#71)

Suggested reviewers

  • dioo1461

Poem

I'm a bunny with a skipping pace,
Hopping through code in a joyful race,
New routes and icons make my day bright,
Optimized images shine in pure light,
With each clever change I twirl and cheer,
Celebrating progress with a happy ear!

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@hamo-o hamo-o changed the title Feature/fe/landing markup [FE-Feat] 랜딩페이지 마크업 및 이미지 webp 변환 스크립트 구현 Feb 6, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (7)
frontend/src/scripts/optimize-image.cjs (1)

1-10: Consider using TypeScript for better type safety.

The script setup looks good, but converting it to TypeScript would provide better type safety and improved IDE support.

-const fs = require("fs");
-const path = require("path");
-const sharp = require("sharp");
+import * as fs from 'fs';
+import * as path from 'path';
+import sharp from 'sharp';

+interface Breakpoint {
+  width: number;
+  suffix: string;
+}

-const BREAKPOINTS = [
+const BREAKPOINTS: Breakpoint[] = [
frontend/src/components/Text/index.tsx (1)

3-4: LGTM! Consider documenting the className prop.

The className prop addition and clsx usage are well implemented. Consider adding JSDoc comments to document the purpose and usage of the className prop for better developer experience.

 interface TextProps extends PropsWithChildren {
   typo?: Typo;
   color?: string;
+  /** Additional CSS classes to be applied to the text element */
   className?: string;
 }

Also applies to: 12-12, 15-16

frontend/src/routes/landing/@components/LandingImages.tsx (1)

1-18: LGTM! Clean implementation with good accessibility.

The component follows React best practices, uses descriptive alt text for accessibility, and implements webp format as requested.

Consider adding loading state handling to improve user experience:

 export const LandingImages = () => (
   <div className={imageWrapperStyle}>
     <Image
       alt='구글 캘린더 연동으로 간편하고 빠른 일정입력'
       className={imageStyle}
+      isLazy={true}
       src='/images/landing/landing-1.webp'
     />
     <Image
       alt='참여자들의 일정을 고려한 추천으로 간단하게 끝나는 일정 조율'
       className={imageStyle}
+      isLazy={true}
       src='/images/landing/landing-2.webp'
     />
   </div>
 );
frontend/src/components/Image/index.tsx (1)

8-14: Move breakpoints to theme configuration.

Consider moving the breakpoints to the theme configuration for better maintainability and consistency across components.

-const BREAKPOINTS = [480, 768, 1280];
-const SIZES = `
-(max-width: 480px) 480px,
-(max-width: 768px) 768px,
-(max-width: 1280px) 1280px,
-(min-width: 1281px) 1920px
-`;
+import { vars } from '@/theme/index.css';
+
+const BREAKPOINTS = vars.breakpoints;
+const SIZES = Object.entries(BREAKPOINTS)
+  .map(([key, value]) => `(max-width: ${value}px) ${value}px`)
+  .join(',\n') + ',\n(min-width: 1281px) 1920px';
frontend/src/routes/landing/@components/index.tsx (2)

22-44: Consider adding i18n support.

The text content is currently hardcoded in Korean. Consider using an i18n library for better maintainability and future localization support.

Example using react-i18next:

+import { useTranslation } from 'react-i18next';
 
 const Landing = () => {
+  const { t } = useTranslation();
   const handleClickGoogleLogin = () => {
     // do something
   };
 
   return (
     <div className={containerStyle}>
       <h1 className={titleStyle}>
-        언제 만나?
+        {t('landing.title')}
       </h1>
       <h2 className={subTitleStyle}>
-        더이상 고민하지 마세요!
+        {t('landing.subtitle')}
       </h2>
       <Text
         className={descriptionStyle}
         color={vars.color.Ref.Netural[700]}
         typo='b2M'
       >
-        당신과 모두의 일정을 하나로 연결해 가장 완벽한 약속 시간을 찾아드려요 
+        {t('landing.description.line1')}
         <br />
-        당신과 모두의 시간을 위해, 지금 바로 시작하세요.
+        {t('landing.description.line2')}
       </Text>
       <Button
         className={buttonStyle}
         leftIcon={<Google />}
         onClick={handleClickGoogleLogin}
         size='xl'
       >
-        Google로 시작하기
+        {t('landing.googleButton')}
       </Button>

29-31: Create color constant for better maintainability.

Consider creating a semantic color constant instead of directly using the color value from theme vars.

+const DESCRIPTION_COLOR = vars.color.Ref.Netural[700];
+
 const Landing = () => {
   return (
     // ...
     <Text
       className={descriptionStyle}
-      color={vars.color.Ref.Netural[700]}
+      color={DESCRIPTION_COLOR}
       typo='b2M'
     >
frontend/src/components/Icon/component/Google.tsx (1)

2-2: Consider using more specific prop types.

Instead of spreading ...rest, consider explicitly defining the SVG attributes you expect to receive for better type safety.

-import type { IconProps } from '../Icon.d.ts';
+import type { IconProps } from '../Icon.d.ts';
+import type { SVGAttributes } from 'react';
 
-export const Google = ({ clickable = false, className, width = 24 , fill = "white", ...rest }: IconProps) => {
+export const Google = ({ 
+  clickable = false, 
+  className, 
+  width = 24, 
+  fill = "white", 
+  ...rest 
+}: IconProps & Omit<SVGAttributes<SVGElement>, keyof IconProps>) => {

Also applies to: 4-4

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49606ed and 20d6f4b9c2c58566ba062a7391c74f2a7ead1946.

⛔ Files ignored due to path filters (2)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/src/components/Icon/svg/google.svg is excluded by !**/*.svg
📒 Files selected for processing (14)
  • frontend/package.json (2 hunks)
  • frontend/src/components/Button/index.tsx (3 hunks)
  • frontend/src/components/Icon/component/Google.tsx (1 hunks)
  • frontend/src/components/Icon/index.ts (1 hunks)
  • frontend/src/components/Image/index.tsx (1 hunks)
  • frontend/src/components/Text/index.tsx (1 hunks)
  • frontend/src/routeTree.gen.ts (5 hunks)
  • frontend/src/routes/index.lazy.tsx (0 hunks)
  • frontend/src/routes/index.tsx (1 hunks)
  • frontend/src/routes/landing/@components/LandingImages.tsx (1 hunks)
  • frontend/src/routes/landing/@components/index.css.ts (1 hunks)
  • frontend/src/routes/landing/@components/index.tsx (1 hunks)
  • frontend/src/routes/landing/index.tsx (1 hunks)
  • frontend/src/scripts/optimize-image.cjs (1 hunks)
💤 Files with no reviewable changes (1)
  • frontend/src/routes/index.lazy.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Send PR Notification to Reviewers
🔇 Additional comments (9)
frontend/package.json (1)

16-16: LGTM! Script and dependency look good.

The script name is descriptive and the sharp version is up to date.

Also applies to: 58-58

frontend/src/routes/landing/index.tsx (1)

1-7: LGTM! Clean and standard route setup.

The route is correctly configured using @tanstack/react-router's createFileRoute with proper component association.

frontend/src/routes/index.tsx (1)

1-9: LGTM! Clean root route with proper redirection.

The root route is correctly configured to redirect to the landing page using @tanstack/react-router's beforeLoad hook.

frontend/src/components/Icon/index.ts (1)

7-7: LGTM! Verify the Google icon implementation.

The export follows the consistent pattern used for other icon components.

Please ensure that the Google icon component in ./component/Google.tsx:

  1. Follows the same implementation pattern as other icon components
  2. Includes proper SVG attributes for accessibility
  3. Has appropriate default props for width, height, and colors

Run this script to verify:

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Check if the Google icon component follows the same pattern as other icons
ast-grep --pattern $'const Google = ({ clickable, className, width, fill, ...rest }: IconProps) => {
  $$$
  return (
    <svg
      $$$
      aria-hidden="true"
      $$$
    >
      $$$
    </svg>
  );
};' frontend/src/components/Icon/component/Google.tsx

Length of output: 258


🏁 Script executed:

#!/bin/bash
echo "=== Checking for 'Google' component definition in Google.tsx ==="
rg "const Google" frontend/src/components/Icon/component/Google.tsx

echo ""
echo "=== Checking for SVG accessibility attribute 'aria-hidden' in Google.tsx ==="
rg "aria-hidden=" frontend/src/components/Icon/component/Google.tsx

echo ""
echo "=== Checking for default props definitions in Google.tsx ==="
rg "defaultProps" frontend/src/components/Icon/component/Google.tsx

Length of output: 783


🏁 Script executed:

#!/bin/bash
# Extract and show the <svg> element and its attributes from the Google icon file for manual inspection.
rg "<svg" frontend/src/components/Icon/component/Google.tsx -n -C 10

Length of output: 1684


Google Icon Implementation Verified

  • The component uses inline default props (clickable, width, fill) consistent with other icon components.
  • The <svg> element includes accessibility attributes via aria-label="google icon", which provides a clear accessible name.
  • The implementation pattern (export, component definition, and inline defaults) is consistent with the other icons.
frontend/src/components/Image/index.tsx (1)

16-33: Add error handling and document file naming convention.

The component assumes specific file naming convention for responsive images but lacks error handling.

  1. Document the required file naming convention in the component's JSDoc:
+/**
+ * Image component with responsive image support.
+ * Required file naming convention for responsive images:
+ * - Base file: image.webp
+ * - Responsive files: image-480w.webp, image-768w.webp, image-1280w.webp
+ */
 export const Image = ({ src, alt, isLazy = false, className }: ImageProps) => {
  1. Add error handling for missing responsive images:
 export const Image = ({ src, alt, isLazy = false, className }: ImageProps) => {
   const BASE_PATH = src.split('.')[0];
+  const [basePath, extension] = src.split('.');
+  
+  if (extension !== 'webp') {
+    console.warn(`Image ${src} should use webp format for better performance`);
+  }
+
   const createSrcSet = () =>
     BREAKPOINTS
       .map((width) => `${BASE_PATH}-${width}w.webp ${width}w`)
       .join(', ');

   return (
     <img
       alt={alt}
       className={className}
       loading={isLazy ? 'lazy' : 'eager'}
       sizes={SIZES}
       src={src}
       srcSet={`${createSrcSet()}, ${src} 1920w`}
+      onError={(e) => {
+        // Fallback to original src if responsive images fail to load
+        e.currentTarget.srcset = '';
+      }}
     />
   );
 };
✅ Verification successful

Action Required: Documentation and Error Handling Updated in Image Component

The revisions in the component now include JSDoc comments that outline the required file naming convention for responsive images, and error handling has been added to warn developers if the image extension isn’t in the expected webp format, as well as to provide a fallback via the onError handler.

  • JSDoc documents the required file naming convention.
  • A warning is issued if the image file extension isn’t “webp”.
  • An onError handler is provided to remove the srcSet fallback if responsive images fail to load.
frontend/src/components/Button/index.tsx (1)

18-19: LGTM! Clean implementation of className prop.

The changes correctly implement the optional className prop with proper TypeScript typing and class name composition using clsx.

Also applies to: 30-35

frontend/src/components/Icon/component/Google.tsx (1)

6-11: LGTM! Well-implemented SVG with accessibility.

The SVG implementation is clean with proper accessibility attributes and dynamic styling.

frontend/src/routes/landing/@components/index.css.ts (1)

65-77: Verify image optimization for responsive sizes.

Based on the PR objectives emphasizing image optimization, ensure that the images are being served in webp format and with appropriate sizes for different viewports.

frontend/src/routeTree.gen.ts (1)

1-142: LGTM! Auto-generated route configuration.

This is an auto-generated file by TanStack Router. The route configuration looks correct with proper type definitions and relationships.

Copy link
Contributor

@dioo1461 dioo1461 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다!

@hamo-o hamo-o force-pushed the feature/fe/landing-markup branch from 8fc73da to fda8dd5 Compare February 6, 2025 12:27
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
frontend/src/routes/landing/@components/index.css.ts (4)

37-43: Remove redundant display property.

The display: 'block' property is unnecessary since text-align works on block elements by default.

export const descriptionStyle = style({
  paddingTop: '0.625rem',
  paddingBottom: '3.375rem',

-  display: 'block',
  textAlign: 'center',
});

45-47: Fix button centering approach.

The justifySelf property only works within a grid layout. For standalone centering, consider using margin or flexbox.

export const buttonStyle = style({
-  justifySelf: 'center',
+  display: 'block',
+  margin: '0 auto',
});

49-63: Maintain consistent horizontal padding.

The horizontal padding is removed in mobile view which might cause content to touch screen edges. Consider maintaining consistent horizontal padding across breakpoints.

export const imageWrapperStyle = style({  
  padding: '3rem 1.75rem 0',

  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  gap: vars.spacing[700],
    
  '@media': {
    '(max-width: 1024px)': {
      flexDirection: 'column',
-      padding: '3rem 0',
+      padding: '3rem 1.75rem',
    },
  },
});

65-77: Optimize image height for mobile devices.

Increasing maxHeight on mobile devices might lead to unnecessarily large images and potential performance issues. Consider reducing or maintaining the same maxHeight for better mobile optimization.

export const imageStyle = style({
  width: '50%',
  maxHeight: '29.8rem',

  objectFit: 'cover',

  '@media': {
    '(max-width: 1024px)': {
      width: '100%',
-      maxHeight: '40rem',
+      maxHeight: '29.8rem',
    },
  },
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20d6f4b9c2c58566ba062a7391c74f2a7ead1946 and fda8dd5.

⛔ Files ignored due to path filters (2)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/src/components/Icon/svg/google.svg is excluded by !**/*.svg
📒 Files selected for processing (13)
  • frontend/package.json (2 hunks)
  • frontend/src/components/Button/index.tsx (1 hunks)
  • frontend/src/components/Icon/component/Google.tsx (1 hunks)
  • frontend/src/components/Icon/index.ts (1 hunks)
  • frontend/src/components/Image/index.tsx (1 hunks)
  • frontend/src/routeTree.gen.ts (5 hunks)
  • frontend/src/routes/index.lazy.tsx (0 hunks)
  • frontend/src/routes/index.tsx (1 hunks)
  • frontend/src/routes/landing/@components/LandingImages.tsx (1 hunks)
  • frontend/src/routes/landing/@components/index.css.ts (1 hunks)
  • frontend/src/routes/landing/@components/index.tsx (1 hunks)
  • frontend/src/routes/landing/index.tsx (1 hunks)
  • frontend/src/scripts/optimize-image.cjs (1 hunks)
💤 Files with no reviewable changes (1)
  • frontend/src/routes/index.lazy.tsx
🚧 Files skipped from review as they are similar to previous changes (10)
  • frontend/src/components/Icon/index.ts
  • frontend/src/routes/landing/@components/LandingImages.tsx
  • frontend/src/routes/index.tsx
  • frontend/src/routes/landing/index.tsx
  • frontend/src/components/Button/index.tsx
  • frontend/package.json
  • frontend/src/components/Icon/component/Google.tsx
  • frontend/src/routes/landing/@components/index.tsx
  • frontend/src/scripts/optimize-image.cjs
  • frontend/src/components/Image/index.tsx
🔇 Additional comments (7)
frontend/src/routes/landing/@components/index.css.ts (3)

6-12: Fix potential horizontal overflow.

Using 100vw can cause horizontal scrolling due to the scrollbar width. Consider using 100% instead.


14-26: Verify font sizes for mobile devices.

The font size of 3.25rem (52px) might be too large for mobile screens. Consider adding responsive font sizes.


28-35: Fix typo in color token name.

There's a typo in the color token name: Netural should be Neutral.

Verify font sizes for mobile devices.

The font size of 3.25rem (52px) might be too large for mobile screens. Consider adding responsive font sizes.

frontend/src/routeTree.gen.ts (4)

1-9: ⚠️ Warning: This is an auto-generated file.

The file header explicitly states that this is automatically generated by TanStack Router and should not be modified manually. Any direct changes to this file will be overwritten. Instead, update your route configurations in their respective source files.


47-70: Type declarations look good!

The type declarations for the landing route are properly integrated across all necessary interfaces, maintaining type safety and consistency.

Also applies to: 75-101


119-141: Route manifest is properly updated.

The route manifest correctly includes the landing route with the appropriate file path.


15-17: Consider performance impact of removing lazy loading.

The IndexRoute has been changed from lazy loading to direct import. While this simplifies the code, it might impact initial load performance. Consider keeping lazy loading if the index route contains heavy components or is not frequently accessed.

Run this script to analyze the bundle size impact:

Also applies to: 25-29

@hamo-o hamo-o merged commit e359ef8 into dev Feb 6, 2025
1 check passed
@hamo-o hamo-o deleted the feature/fe/landing-markup branch February 6, 2025 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🖥️ FE Frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 랜딩페이지

3 participants