Skip to content

Commit

Permalink
feat: accordion 추가 및 ui/ux 개선
Browse files Browse the repository at this point in the history
  • Loading branch information
ssi02014 committed Feb 25, 2023
1 parent a7f134c commit 07b41a4
Show file tree
Hide file tree
Showing 12 changed files with 420 additions and 298 deletions.
37 changes: 37 additions & 0 deletions src/components/Accordion/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useState } from 'react';
import * as S from './styled';
import { arrowBottom, arrowTop } from '../../assets/icons';
import TGIcon from '../../components/TGIcon';

interface AccordionProps {
title: string;
children: React.ReactNode;
}

const Accordion = ({ title, children }: AccordionProps) => {
const [isOpenPanel, setIsOpenPanel] = useState(false);

const handleToggle = () => {
setIsOpenPanel(!isOpenPanel);
};

return (
<S.AccordionWrapper>
<S.AccordionTopContainer onClick={handleToggle}>
<p>{title}</p>
<span>
{isOpenPanel ? (
<TGIcon src={arrowTop} width={14} height={14} />
) : (
<TGIcon src={arrowBottom} width={14} height={14} />
)}
</span>
</S.AccordionTopContainer>
<S.AccordionPanelContainer className={isOpenPanel ? 'active' : ''}>
{children}
</S.AccordionPanelContainer>
</S.AccordionWrapper>
);
};

export default Accordion;
49 changes: 49 additions & 0 deletions src/components/Accordion/styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import styled from 'styled-components';

export const AccordionWrapper = styled.div`
margin: 0 auto;
width: 100%;
`;

export const AccordionTopContainer = styled.div`
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: 0.3s;
padding: 0 20px;
height: 39px;
& > p {
cursor: pointer;
background-color: transparent;
outline: none;
border: none;
text-align: start;
font-size: 1rem;
color: #111;
margin: 0;
}
&:hover {
& > p {
color: #3264b5;
}
}
`;

export const AccordionPanelContainer = styled.div`
background-color: #fff;
overflow: hidden;
transition: max-height 0.3s linear;
max-height: 0;
& > p {
padding: 20px 40px;
font-size: 1.15rem;
}
&.active {
max-height: 200px;
}
`;
23 changes: 10 additions & 13 deletions src/components/TGCanvas.tsx → src/components/Canvas/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import React, { useEffect } from 'react';
import { Color } from 'react-color-palette';
import { CanvasState } from '../types/canvas';
import { TGCanvasWrapper } from './TG.styled';
import { CanvasState } from '../../types/canvas';
import * as S from './styled';

interface TGCanvasProps {
interface CanvasProps {
canvasState: CanvasState;
bgColor: Color;
fontColor: Color;
strokeColor: Color;
}

const TGCanvas = React.forwardRef(
(
{ canvasState, bgColor, fontColor, strokeColor }: TGCanvasProps,
ref: any
) => {
const Canvas = React.forwardRef(
({ canvasState, bgColor, fontColor, strokeColor }: CanvasProps, ref: any) => {
const {
value,
canvasWidth,
Expand Down Expand Up @@ -84,7 +81,7 @@ const TGCanvas = React.forwardRef(
if (ctx) {
ctx.save();

if (isBlur) ctx.filter = 'blur(4px)'; // (*)
if (isBlur) ctx.filter = 'blur(5px)'; // (*)
if (selectedImage) {
ctx.drawImage(selectedImage, 0, 0);
} else {
Expand All @@ -98,13 +95,13 @@ const TGCanvas = React.forwardRef(
}, [bgColor, fontColor, strokeColor, canvasState]);

return (
<TGCanvasWrapper>
<S.CanvasWrapper>
<canvas ref={ref} width={+canvasWidth} height={+canvasHeight} />
</TGCanvasWrapper>
</S.CanvasWrapper>
);
}
);

TGCanvas.displayName = 'Search';
Canvas.displayName = 'Search';

export default TGCanvas;
export default Canvas;
7 changes: 7 additions & 0 deletions src/components/Canvas/styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styled from 'styled-components';

export const CanvasWrapper = styled.div`
display: flex;
justify-content: center;
width: 100%;
`;
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import React, { useEffect, useRef, useState } from 'react';
import { TGColorPickerWrapper, TGIConButton } from './TG.styled';
import { Color, ColorPicker } from 'react-color-palette';
import { ColorPickerWrapper } from './styled';
import { Color, ColorPicker as PaletteColorPicker } from 'react-color-palette';
import { IconButton } from '../Icon/styled';

interface TGColorPickerProps {
interface ColorPickerPickerProps {
children: React.ReactNode;
color: Color;
setColor: (color: Color) => void;
}
const TGColorPicker = ({ children, color, setColor }: TGColorPickerProps) => {
const ColorPickerPicker = ({
children,
color,
setColor,
}: ColorPickerPickerProps) => {
const [isOpenColorPicker, setIsOpenColorPicker] = useState(false);
const colorRef = useRef<HTMLDivElement>(null);

Expand All @@ -34,16 +39,16 @@ const TGColorPicker = ({ children, color, setColor }: TGColorPickerProps) => {
}, [handleCloseColorPicker]);

return (
<TGColorPickerWrapper>
<TGIConButton
<ColorPickerWrapper>
<IconButton
isOpenColorPicker={isOpenColorPicker}
onClick={handleOpenColorPicker}
isBorder={true}>
{children}
</TGIConButton>
</IconButton>
{isOpenColorPicker && (
<div ref={colorRef}>
<ColorPicker
<PaletteColorPicker
width={250}
height={150}
color={color}
Expand All @@ -54,8 +59,8 @@ const TGColorPicker = ({ children, color, setColor }: TGColorPickerProps) => {
/>
</div>
)}
</TGColorPickerWrapper>
</ColorPickerWrapper>
);
};

export default TGColorPicker;
export default ColorPickerPicker;
143 changes: 143 additions & 0 deletions src/components/ColorPicker/styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import styled from 'styled-components';

export const ColorPickerWrapper = styled.div`
position: relative;
& > div {
position: absolute;
left: 50%;
bottom: 40px;
transform: translateX(-50%);
}
.rcp-light {
--rcp-background: #ffffff;
--rcp-input-text: #111111;
--rcp-input-border: rgba(0, 0, 0, 0.1);
--rcp-input-label: #717171;
}
.rcp-dark {
--rcp-background: #181818;
--rcp-input-text: #f3f3f3;
--rcp-input-border: rgba(255, 255, 255, 0.1);
--rcp-input-label: #999999;
}
.rcp {
display: flex;
flex-direction: column;
align-items: center;
background-color: var(--rcp-background);
border-radius: 10px;
}
.rcp-body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
width: 100%;
box-sizing: border-box;
padding: 20px;
}
.rcp-saturation {
position: relative;
width: 100%;
background-image: linear-gradient(transparent, black),
linear-gradient(to right, white, transparent);
border-radius: 10px 10px 0 0;
user-select: none;
}
.rcp-saturation-cursor {
position: absolute;
width: 20px;
height: 20px;
border: 2px solid #ffffff;
border-radius: 50%;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.15);
box-sizing: border-box;
transform: translate(-10px, -10px);
}
.rcp-hue {
position: relative;
width: 100%;
height: 12px;
background-image: linear-gradient(
to right,
rgb(255, 0, 0),
rgb(255, 255, 0),
rgb(0, 255, 0),
rgb(0, 255, 255),
rgb(0, 0, 255),
rgb(255, 0, 255),
rgb(255, 0, 0)
);
border-radius: 10px;
user-select: none;
}
.rcp-hue-cursor {
position: absolute;
width: 20px;
height: 20px;
border: 2px solid #ffffff;
border-radius: 50%;
box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 0px 0.5px;
box-sizing: border-box;
transform: translate(-10px, -4px);
}
.rcp-alpha {
position: relative;
width: 100%;
height: 12px;
border-radius: 10px;
user-select: none;
}
.rcp-alpha-cursor {
position: absolute;
width: 20px;
height: 20px;
border: 2px solid #ffffff;
border-radius: 50%;
box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 0px 0.5px;
box-sizing: border-box;
transform: translate(-10px, -4px);
}
.rcp-fields {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
width: 100%;
}
.rcp-fields-element {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
width: 100%;
}
.hex-element {
grid-row: 1;
}
.hex-element:nth-child(3n) {
grid-column: 1 / -1;
}
.rcp-fields-element-input {
width: 100%;
font-size: 14px;
font-weight: 600;
color: var(--rcp-input-text);
text-align: center;
background: none;
border: 2px solid;
border-color: var(--rcp-input-border);
border-radius: 5px;
box-sizing: border-box;
outline: none;
padding: 10px;
}
.rcp-fields-element-label {
font-size: 14px;
font-weight: 600;
color: var(--rcp-input-label);
text-transform: uppercase;
}
`;
13 changes: 13 additions & 0 deletions src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';

interface IconProps {
src: string;
width: number;
height: number;
}

const Icon = ({ src, width, height }: IconProps) => {
return <img src={src} width={width} height={height} />;
};

export default Icon;
26 changes: 26 additions & 0 deletions src/components/Icon/styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import styled from 'styled-components';

export const IconButton = styled.button<{
isOpenColorPicker?: boolean;
isBorder?: boolean;
}>`
padding: 4px 5px;
background: #fff;
border-radius: 5px;
display: flex;
align-items: center;
cursor: pointer;
${({ isBorder, isOpenColorPicker }) => {
if (!isBorder) return `border: none;`;
return `
border: ${
isOpenColorPicker ? '1px solid #0e1b30;' : '1px solid #cccccc;'
};
`;
}}
&:hover {
border: ${({ isBorder }) => (isBorder ? `1px solid #0e1b30` : 'none')};
}
`;
Loading

0 comments on commit 07b41a4

Please sign in to comment.