๐ŸŒธ ๋งˆ๋‹ˆ๋˜ ๋ฉ”์ด์ปค ๋ด„ ๋Œ€๋น„ ์—…๋ฐ์ดํŠธ

๋ฏธํ‚ค์˜คยท2025๋…„ 2์›” 16์ผ
1

Manitto-Maker

๋ชฉ๋ก ๋ณด๊ธฐ
1/4
post-thumbnail

๋“ค์–ด๊ฐ€๋ฉฐ..

๋งˆ๋‹ˆ๋˜ ๋ฉ”์ด์ปค๋Š” ํ˜„์žฌ๊นŒ์ง€ ์ด 2.5๋งŒ ๋ช… ์ด์ƒ์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์ด์šฉํ•œ ์„œ๋น„์Šค๋กœ ์„ฑ์žฅํ–ˆ๋‹ค. ํŠนํžˆ, ์—ฐ๋ง๊ณผ ํฌ๋ฆฌ์Šค๋งˆ์Šค ์‹œ์ฆŒ์„ ํ™œ์šฉํ•ด ๋งŽ์€ ์œ ์ €๊ฐ€ ์œ ์ž…๋˜์—ˆ๊ณ , ์˜ˆ์ƒ๋ณด๋‹ค SEO(Search Engine Optimization) ํšจ๊ณผ๋ฅผ ๋„ˆ๋ฌด ์ž˜ ๋ฐ›์•„์„œ ํญ๋ฐœ์ ์ธ ํŠธ๋ž˜ํ”ฝ ์ฆ๊ฐ€๋ฅผ ๊ฒฝํ—˜ํ•˜๊ธฐ๋„ ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ณ„์ ˆ์ด ๋ฐ”๋€Œ๋ฉด์„œ ์ƒˆ๋กœ์šด ๋ณ€ํ™”๊ฐ€ ํ•„์š”ํ–ˆ๋‹ค. ๊ฒจ์šธ ๋™์•ˆ react-snowfall์„ ํ™œ์šฉํ•ด ๋ˆˆ์ด ๋‚ด๋ฆฌ๋Š” ํšจ๊ณผ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์—ˆ์ง€๋งŒ, ์Šฌ์Šฌ ๋ด„์ด ๋‹ค๊ฐ€์˜ค๋ฉด์„œ ์ƒˆ ํ•™๊ธฐ, ์ƒˆ๋กœ์šด ์‹œ์ž‘์ด ๋งŽ์€ 3์›”์— ๋งž์ถฐ ๋””์ž์ธ์„ ์—…๋ฐ์ดํŠธํ•ด์•ผ๊ฒ ๋‹ค๋Š” ํ•„์š”์„ฑ์ด ์ƒ๊ฒผ๋‹ค.

๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, Firestore ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€๋กœ ์ธํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋น„์šฉ์ด ์ ์  ์ปค์ง€๋Š” ๋ฌธ์ œ๋„ ๋ฐœ์ƒํ–ˆ๋‹ค. ์ด์— ๋”ฐ๋ผ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ง€์ธ๋“ค๊ณผ ํ•จ๊ป˜ ๋น„์šฉ ์ตœ์ ํ™” ๋ฐ ํŠธ๋ž˜ํ”ฝ ๋ถ„์‚ฐ์„ ์œ„ํ•œ ๋ฐฑ์—”๋“œ ๊ฐœํŽธ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ๊ณ , ๊ทธ ๊ณผ์ •์—์„œ UX ๋ฌธ์ œ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.

๐Ÿ“Œ ์ด๋ฒˆ ์—…๋ฐ์ดํŠธ์˜ ํ•ต์‹ฌ ๋ชฉํ‘œ
โœ”๏ธ ๋ฒš๊ฝƒ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ตฌํ˜„ โ†’ ์ดˆ์† 5cm์˜ ๋‚™ํ•˜ ์†๋„๋ฅผ ์ ์šฉํ•˜์—ฌ ๋ด„ ๋ถ„์œ„๊ธฐ ์กฐ์„ฑ
โœ”๏ธ UX ๊ฐœ์„  โ†’ ๊ทธ๋ฃน ์ƒ์„ฑ ํ›„ ๋น„๋ฐ€๋ฒˆํ˜ธ, ๋ฆฌ๋”๋ช… ์ €์žฅ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ํ•˜์—ฌ ์œ ์ € ํŽธ์˜์„ฑ ํ–ฅ์ƒ
โœ”๏ธ ๋””์ž์ธ ๊ฐœํŽธ โ†’ teal(์ฒญ๋ก์ƒ‰)์—์„œ ์—ฐํ•‘ํฌ ํ…Œ๋งˆ๋กœ UI ๋ณ€๊ฒฝํ•˜์—ฌ ๋ด„ ์ปจ์…‰์— ๋งž์ถค

์ด ๊ธ€์—์„œ๋Š” ๋ฒš๊ฝƒ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ง์ ‘ ๊ตฌํ˜„ํ•œ ๊ณผ์ •, UX๋ฅผ ๊ฐœ์„ ํ•œ ๋ชจ๋‹ฌ ์ถ”๊ฐ€, ๊ทธ๋ฆฌ๊ณ  MUI ํ…Œ๋งˆ๋ฅผ ํ™œ์šฉํ•œ ํ•‘ํฌํ†ค UI ์ ์šฉ ๊ณผ์ •์„ ์ƒ์„ธํžˆ ๋‹ค๋ค„๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

๋ฒš๊ฝƒ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ตฌํ˜„ํ•˜๊ธฐ

๐Ÿ“Œ ๋ฌธ์ œ์ : ๊ธฐ์กด react-snowfall์˜ ํ•œ๊ณ„

์ดˆ๊ธฐ์— ์‚ฌ์šฉํ•œ react-snowfall ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ด๋ฆ„์—์„œ๋„ ๊ทธ ์ •์ฒด์„ฑ์ด ๋‚˜ํƒ€๋‚˜๋“ฏ์ด ๋ˆˆ ๋ชจ์–‘์˜ ์ค‘๋ ฅ ๊ธฐ๋ฐ˜ ๋‚™ํ•˜๋งŒ ์ง€์›ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฒš๊ฝƒ์€ ๊ณต๊ธฐ ์ €ํ•ญ๊ณผ ๋ฐ”๋žŒ์˜ ์˜ํ–ฅ์„ ๋ฐ›์•„ ํฉ๋‚ ๋ฆฌ๋ฉด์„œ ํšŒ์ „ํ•˜๋Š” ํŠน์„ฑ์ด ์žˆ๋‹ค.

๋˜ํ•œ, ๋ฆฌ์•กํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ํ”„๋ ˆ์ž„ ๋‹จ์œ„ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋‹ค๋ฃฐ ์ข‹์€ ํ•™์Šต ๊ธฐํšŒ๊ฐ€ ๋  ๊ฒƒ ๊ฐ™์•˜๊ณ , ์ฃผ๋ง์„ ์ด์šฉํ•ด ์ง์ ‘ ๋ฒš๊ฝƒ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค์–ด ๋ณด๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค! ๐Ÿš€

โœ”๏ธ ๊ธฐ์กด ๋ˆˆ ํšจ๊ณผ โŒ
โœ”๏ธ ๋ฒš๊ฝƒ ํšจ๊ณผ โœ… โ†’ ์ขŒ์šฐ๋กœ ํ”๋“ค๋ฆฌ๋ฉฐ ํšŒ์ „ํ•˜๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋‚™ํ•˜ ๊ตฌํ˜„

๐ŸŽฏ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: Canvas API + requestAnimationFrame() ํ™œ์šฉ

๐Ÿ“Œ ๋ชฉํ‘œ
โœ… ์ดˆ์† 5cm(189px/s) ์†๋„๋กœ ๋–จ์–ด์ง€๋Š” ๋ฒš๊ฝƒ ๊ตฌํ˜„
โœ… ๋ฐ”๋žŒ์— ์˜ํ•ด ํ”๋“ค๋ฆฌ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ์›€์ง์ž„ ์ถ”๊ฐ€
โœ… ๋ฒš๊ฝƒ์ด ํšŒ์ „ํ•˜๋ฉด์„œ ๋‚™ํ•˜ํ•˜๋Š” ํšจ๊ณผ ์ ์šฉ

๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์ˆ 
โœ”๏ธ Canvas API โ†’ <canvas>๋ฅผ ์‚ฌ์šฉํ•ด ์ง์ ‘ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ทธ๋ฆผ
โœ”๏ธ requestAnimationFrame() โ†’ ๋ถ€๋“œ๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์œ„ํ•œ ํ”„๋ ˆ์ž„ ๋‹จ์œ„ ๋ Œ๋”๋ง
โœ”๏ธ Math.sin() ํ•จ์ˆ˜ โ†’ ์ขŒ์šฐ ํ”๋“ค๋ฆผ ํšจ๊ณผ๋ฅผ ์œ„ํ•œ ์ˆ˜ํ•™์  ๊ณ„์‚ฐ
โœ”๏ธ ๋žœ๋ค ๊ฐ’ ์ ์šฉ โ†’ ๋ฒš๊ฝƒ ํฌ๊ธฐ, ์†๋„, ํˆฌ๋ช…๋„๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•˜์—ฌ ํ˜„์‹ค๊ฐ ๊ทน๋Œ€ํ™”

๐Ÿ’ป 1๏ธโƒฃ ์บ”๋ฒ„์Šค ์ƒ์„ฑ ๋ฐ ๊ธฐ๋ณธ ์„ค์ •

์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ Œ๋”๋งํ•  ์บ”๋ฒ„์Šค(Canvas API) ๋ฅผ ์ƒ์„ฑํ•˜๊ณ ,
๋ธŒ๋ผ์šฐ์ € ์ฐฝ ํฌ๊ธฐ์— ๋งž์ถฐ ํฌ๊ธฐ๋ฅผ ์กฐ์ •ํ•œ๋‹ค.

const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

๐Ÿ‘‰ canvas.getContext("2d")๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ 2D ๋“œ๋กœ์ž‰ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ด
๐Ÿ‘‰ window.innerWidth๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „์ฒด ํ™”๋ฉด ํฌ๊ธฐ์— ๋งž์ถฐ ์บ”๋ฒ„์Šค ํฌ๊ธฐ ์„ค์ •

๐ŸŽจ 2๏ธโƒฃ ๋ฒš๊ฝƒ ๊ฐ์ฒด(Petal) ๋งŒ๋“ค๊ธฐ

๊ฐ ๋ฒš๊ฝƒ ์žŽ์€ ์œ„์น˜(x, y), ํฌ๊ธฐ(size), ํšŒ์ „(rotation), ์†๋„(speedX, speedY) ๋ฅผ ๊ฐ–๋Š”๋‹ค.

class Petal {
  constructor() {
    this.x = Math.random() * canvas.width;
    this.y = Math.random() * canvas.height;
    this.size = Math.random() * 4 + 2; 
    this.speedX = Math.random() * 1.5 - 0.75; 
    this.speedY = Math.random() * fallSpeed + 1.5;
    this.rotation = Math.random() * 360;
    this.rotationSpeed = Math.random() * 1.5 - 0.75; 
    this.opacity = Math.random() * 0.7 + 0.3;
  }
}

โœ”๏ธ ๋žœ๋คํ•œ ํฌ๊ธฐ, ์†๋„, ํˆฌ๋ช…๋„ ์„ค์ • โ†’ ๋ฒš๊ฝƒ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณด์ด๋„๋ก ๋ณ€ํ˜•
โœ”๏ธ ์ขŒ์šฐ ํ”๋“ค๋ฆผ ํšจ๊ณผ(speedX) โ†’ ๋ฐ”๋žŒ์— ๋‚ ๋ฆฌ๋Š” ํšจ๊ณผ ๊ตฌํ˜„
โœ”๏ธ ๋žœ๋ค ํšŒ์ „(rotation, rotationSpeed) โ†’ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํšŒ์ „ํ•˜๋ฉด์„œ ๋‚™ํ•˜

๐Ÿƒ 3๏ธโƒฃ ๋ฐ”๋žŒ ํšจ๊ณผ ์ ์šฉํ•˜๊ธฐ (์ขŒ์šฐ ํ”๋“ค๋ฆผ)

๋ฐ”๋žŒ์ด ๋ถˆ๋ฉด ๋ฒš๊ฝƒ์ด ์ขŒ์šฐ๋กœ ํ”๋“ค๋ ค์•ผ ํ•œ๋‹ค.
์ด๋ฅผ ์œ„ํ•ด Math.sin() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ y๊ฐ’(๋‚™ํ•˜ ๊ฑฐ๋ฆฌ)์— ๋”ฐ๋ผ x๊ฐ’์„ ํ”๋“ค๋ฆฌ๊ฒŒ ์„ค์ •ํ–ˆ๋‹ค.

update() {
  this.x += this.speedX + Math.sin(this.y / 90) * windStrength;
  this.y += this.speedY;
  this.rotation += this.rotationSpeed;

  if (this.y > canvas.height) {
    this.y = -10;
    this.x = Math.random() * canvas.width;
    this.speedX = Math.random() * 1.5 - 0.75;
  }
}

โœ”๏ธ Math.sin(this.y / 90) * windStrength
โ†’ y๊ฐ’(๋‚™ํ•˜ ๊ฑฐ๋ฆฌ)์— ๋”ฐ๋ผ x๊ฐ’์ด ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ณ€ํ™”ํ•˜๋ฉด์„œ ์ขŒ์šฐ ํ”๋“ค๋ฆฌ๋Š” ํšจ๊ณผ ์ถ”๊ฐ€
โœ”๏ธ this.speedY += gravity;
โ†’ ๋‚™ํ•˜ ์†๋„๋ฅผ ํ”„๋ ˆ์ž„๋งˆ๋‹ค ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๋ฐฉ์‹(์ค‘๋ ฅ ํšจ๊ณผ)๋„ ๊ณ ๋ คํ–ˆ์ง€๋งŒ, ๋ฒš๊ฝƒ์—๋Š” ์ค‘๋ ฅ์ด ๊ฑฐ์˜ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋žต

๐ŸŒฟ 4๏ธโƒฃ ๋ฒš๊ฝƒ ๊ทธ๋ฆฌ๊ธฐ (์บ”๋ฒ„์Šค์— ๋ Œ๋”๋ง)

๊ฐ ๋ฒš๊ฝƒ ๊ฐ์ฒด์˜ ์œ„์น˜์— ๋ถ€๋“œ๋Ÿฌ์šด ๊ณก์„ ์„ ๊ฐ€์ง„ ๋„ํ˜•์„ ๊ทธ๋ ค์คŒ

draw() {
  ctx.save();
  ctx.translate(this.x, this.y);
  ctx.rotate((this.rotation * Math.PI) / 180);
  ctx.beginPath();
  ctx.moveTo(0, -this.size);
  ctx.quadraticCurveTo(this.size, -this.size, this.size, 0);
  ctx.quadraticCurveTo(this.size, this.size, 0, this.size);
  ctx.quadraticCurveTo(-this.size, this.size, -this.size, 0);
  ctx.quadraticCurveTo(-this.size, -this.size, 0, -this.size);
  ctx.fillStyle = `rgba(255, 182, 193, ${this.opacity})`;
  ctx.fill();
  ctx.restore();
}

โœ”๏ธ ctx.translate(this.x, this.y) โ†’ ๊ฐ ๋ฒš๊ฝƒ์˜ ์œ„์น˜๋กœ ์ด๋™
โœ”๏ธ ctx.rotate((this.rotation * Math.PI) / 180) โ†’ ํšŒ์ „ ํšจ๊ณผ ์ ์šฉ
โœ”๏ธ ctx.fillStyle = rgba(255, 182, 193, this.opacity) โ†’ ์—ฐํ•‘ํฌ ๊ณ„์—ด ์ƒ‰์ƒ ์ ์šฉ

๐ŸŽฌ 5๏ธโƒฃ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฃจํ”„ ์‹คํ–‰ (requestAnimationFrame)

์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ง€์†์ ์œผ๋กœ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์žฌ๊ท€์ ์œผ๋กœ animate()๋ฅผ ํ˜ธ์ถœ

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  petals.forEach((petal) => {
    petal.update();
    petal.draw();
  });
  requestAnimationFrame(animate);
}

โœ”๏ธ ctx.clearRect(0, 0, canvas.width, canvas.height) โ†’ ๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ์บ”๋ฒ„์Šค๋ฅผ ์ง€์šฐ๊ณ  ๋‹ค์‹œ ๊ทธ๋ฆผ
โœ”๏ธ requestAnimationFrame(animate) โ†’ ๋ถ€๋“œ๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹คํ–‰

๊ทธ ๊ฒฐ๊ณผ ์ดˆ์† 5cm๋ฅผ ์ค€์ˆ˜ํ•œ ๋ง˜์— ๋“œ๋Š” ๋ฒš๊ฝƒ ํšจ๊ณผ๊ฐ€ ์ƒ๊ฒผ๋‹ค!

๐ŸŽจ UI ๋””์ž์ธ ๊ฐœ์„  - ํ•‘ํฌ ํ…Œ๋งˆ ์ ์šฉ

๐Ÿ“Œ ๊ธฐ์กด ๋””์ž์ธ ๋ฌธ์ œ

โŒ ๊ธฐ์กด ํฌ๋ฆฌ์Šค๋งˆ์Šค์— ๋งž์ถ˜ teal(์ฒญ๋ก์ƒ‰) + red ์ƒ‰์ƒ์ด ๋ด„ ํ…Œ๋งˆ์™€ ์–ด์šธ๋ฆฌ์ง€ ์•Š์Œ
โŒ ๋ฒ„ํŠผ ์ƒ‰์ƒ์ด ์ผ๊ด€๋˜์ง€ ์•Š์•„ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง
โŒ UI ์š”์†Œ ๊ฐ„๊ฒฉ๊ณผ ์ƒ‰์ƒ ์กฐํ•ฉ์ด ์–ด์ƒ‰ํ•˜์—ฌ ๋””์ž์ธ ํ€„๋ฆฌํ‹ฐ ์ €ํ•˜

โœ… ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• - MUI ํ…Œ๋งˆ ํ™œ์šฉ

๐Ÿ“Œ MUI ํ…Œ๋งˆ ์ ์šฉ ์ฝ”๋“œ

const theme = createTheme({
  palette: {
    primary: {
      main: "#FF85A2", // ์—ฐํ•‘ํฌ ํ…Œ๋งˆ
    },
    secondary: {
      main: "#FF5C8A", // ๋ณด์กฐ ์ƒ‰์ƒ
    },
  },
});

๐Ÿ‘‰ ThemeProvider๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ฑ ์ „๋ฐ˜์— ๊ฑธ์ณ ํ•‘ํฌ ํ…Œ๋งˆ ์ ์šฉ

๐Ÿ“Œ ๋ฒ„ํŠผ ์ปฌ๋Ÿฌ ์ ์šฉ

<Button
  variant="outlined"
  sx={{
    color: "#D81B60", // ํ•‘ํฌ ํฌ์ธํŠธ
    borderColor: "#D81B60",
    "&:hover": { backgroundColor: "#FFE3E3" }, // ์—ฐํ•‘ํฌ ํšจ๊ณผ
  }}
>
  ๋ฉ”์ธ์œผ๋กœ
</Button>

๐Ÿ‘‰ ๊ธฐ์กด teal์„ ๋”ฅํ•‘ํฌ(#D81B60) ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ด„์— ์–ด์šธ๋ฆฌ๋Š” UI ์™„์„ฑ

๐Ÿ” UX ๊ฐœ์„  - ๊ทธ๋ฃน ์ •๋ณด ํ™•์ธ ๋ชจ๋‹ฌ ์ถ”๊ฐ€

๐Ÿ“Œ UX ๋ฌธ์ œ ๋ฐœ๊ฒฌ: ์œ ์ €๋“ค์ด ๊ทธ๋ฃน ์ •๋ณด๋ฅผ ์žŠ์–ด๋ฒ„๋ฆฌ๋Š” ๋ฌธ์ œ

๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ๋…ผ์˜ํ•˜๋Š” ๊ณผ์ •์—์„œ, ์œ ์ €๊ฐ€ ๊ทธ๋ฃน์„ ์ƒ์„ฑํ•œ ํ›„ ๋น„๋ฐ€๋ฒˆํ˜ธ, ๋ฆฌ๋”๋ช…, ๊ทธ๋ฃน๋ช…์„ ์žŠ์–ด๋ฒ„๋ฆฌ๊ณ  ๋‹ค์‹œ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

๐Ÿ“Œ ์‹ค์ œ ๋ฐ์ดํ„ฐ ๋ถ„์„ ๊ฒฐ๊ณผ

โœ”๏ธ ๋™์ผํ•œ ๋ฆฌ๋”๋ช… + ์‚ด์ง ๋‹ค๋ฅธ ๊ทธ๋ฃน๋ช…์„ ์ ์šฉํ•ด ๋‹ค์‹œ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋นˆ๋ฒˆ
โœ”๏ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ค‘๋ณต๋œ ๊ทธ๋ฃน์ด ์ง€์†์ ์œผ๋กœ ์ถ”๊ฐ€๋˜๋ฉด์„œ ๋น„์šฉ ์ฆ๊ฐ€

๐Ÿ“Œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

โœ… ๊ทธ๋ฃน ์ƒ์„ฑ ํ›„ "์ •๋ณด ํ™•์ธ ๋ชจ๋‹ฌ" ์ถ”๊ฐ€
โœ… ํด๋ฆฝ๋ณด๋“œ ๋ณต์‚ฌ ๊ธฐ๋Šฅ & ์นด์นด์˜คํ†ก ๊ณต์œ  ๊ธฐ๋Šฅ ์ ์šฉ
โœ… ์œ ์ €๊ฐ€ ์ •๋ณด๋ฅผ ์‰ฝ๊ฒŒ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก UX ๊ฐœ์„ 

๐Ÿ“Œ GroupInfoModal.jsx

<Button onClick={onCopy} sx={{ backgroundColor: "#FF85A2" }}>
  ํด๋ฆฝ๋ณด๋“œ ๋ณต์‚ฌ
</Button>
<Button onClick={onShare} sx={{ backgroundColor: "#FFD700" }}>
  ์นด์นด์˜คํ†ก ๊ณต์œ 
</Button>

๐Ÿ‘‰ ํด๋ฆฝ๋ณด๋“œ ๋ณต์‚ฌ ๋ฒ„ํŠผ๊ณผ ์นด์นด์˜คํ†ก ๊ณต์œ  ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ•˜์—ฌ, ์œ ์ €๊ฐ€ ์ •๋ณด๋ฅผ ์‰ฝ๊ฒŒ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.


๋˜ํ•œ ์นดํ†ก ๋‚˜์—๊ฒŒ ์ „์†ก ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์ด์ „๋ณด๋‹ค ๋” ํŽธํ•˜๊ฒŒ ๋‚˜์˜ ์ •๋ณด๋ฅผ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

๐Ÿ’ก ๋งˆ๋ฌด๋ฆฌ

์ด๋ฒˆ ์—…๋ฐ์ดํŠธ๋ฅผ ํ†ตํ•ด,
โœ”๏ธ Canvas API๋ฅผ ํ™œ์šฉํ•œ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฒš๊ฝƒ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ตฌํ˜„
โœ”๏ธ ๋ฐฑ์—”๋“œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ตœ์ ํ™”๋ฅผ ์œ„ํ•œ UX ๊ฐœ์„ 
โœ”๏ธ MUI ํ…Œ๋งˆ ์„ค์ •์„ ํ™œ์šฉํ•œ UI ๋””์ž์ธ ๊ฐœ์„ 

๋ฅผ ์™„์ˆ˜ํ–ˆ๋‹ค :D

๊ธฐ๋Šฅ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก UI/UX๋ฅผ ๊ณ ๋ฏผํ•˜๋Š” ๊ณผ์ •์ด ์ค‘์š”ํ•˜๋‹ค๋Š” ์ ์„ ๋‹ค์‹œ ํ•œ๋ฒˆ ๊นจ๋‹ฌ์•˜๋‹ค.

์ด์ œ ๋งˆ๋‹ˆ๋˜ ๋ฉ”์ด์ปค๋Š” ๋” ๊ฐ์„ฑ์ ์ธ ๋ด„ ์„œ๋น„์Šค๊ฐ€ ๋˜์—ˆ๋‹ค!
์•„์ง 2์›” ์ค‘์ˆœ์ด๋‹ค

profile
๊ต์œก ์ „๊ณต ๊ฐœ๋ฐœ์ž ๐Ÿ’ป

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด