치춘짱베리굿나이스
[프리온보딩] 220503 강의 메모 04 (투두 리스트 예시) 본문
투두리스트 작성 예시
dribble.com
디자이너들끼리의 커뮤니티(?) 로, 사람들이 만든 웹 디자인들이 올라온다
Figma 없이 하나의 테마만 갖고 작업할 때 참고하기 좋다
다만 디자이너들이 온갖 기교를 넣어서 만들어놓은 동작이나 애니메이션이 많기 때문에 쳐낼 기능은 쳐내면서 작업하자..
ColorSlurp
화면상의 색상을 찍어 색상코드를 받아올 수 있는 프로그램 (mac용)
프로젝트 초기화 하기
.eslintrc.json
{
"extends": ["airbnb", "airbnb/hooks", "react-app", "prettier"],
"env": {
"browser": true,
"jasmine": true,
"jest": true
},
"settings": {
"import/extensions": [".js", ".jsx"],
"import/resolver": {
"node": {
"extensions": [".js", ".jsx"]
}
},
"react": {
"pragma": "React",
"version": "detect"
}
},
"rules": {
"arrow-body-style": "off",
"semi": ["warn", "never"],
"react/jsx-one-expression-per-line": "off",
"react/jsx-filename-extension": [
"error",
{ "extensions": [".js", ".jsx"] }
],
"react/jsx-indent": "warn",
"react/jsx-props-no-spreading": "off",
"react/no-array-index-key": "warn",
"react/require-default-props": "off",
"react/jsx-wrap-multilines": "off",
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off",
"import/prefer-default-export": "off",
"import/no-unresolved": "off",
"import/order": "off",
"import/no-anonymous-default-export": "off",
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": [".storybook/**", "src/stories/**"]
}
],
// "max-lines": ["warn", 150],
"no-param-reassign": ["error", { "props": false }],
"no-use-before-define": "off",
"no-shadow": "off",
"no-unused-expressions": ["warn"],
"prefer-const": ["warn"],
"prefer-destructuring": ["error", { "object": true, "array": false }],
"lines-between-class-members": "off",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/label-has-associated-control": [
"error",
{
"labelComponents": ["label"],
"labelAttributes": ["htmlFor"],
"controlComponents": ["input"]
}
],
"import/extensions": [
"error",
"ignorePackages",
{
"js": "never",
"jsx": "never"
}
]
}
}
.prettierrc.yml
jsxSingleQuote: true
semi: false
printWidth: 120
proseWrap: never
singleQuote: true
htmlWhitespaceSensitivity: "css"
endOfLine: "lf"
.stylelintrc.json
{
"extends": ["stylelint-config-standard-scss", "stylelint-config-recess-order"],
"overrides": [
{
"files": ["**/*.scss"],
"customSyntax": "postcss-scss"
}
],
"plugins": ["stylelint-declaration-strict-value"],
"rules": {
"at-rule-empty-line-before": null,
"color-function-notation": "legacy",
"color-hex-case": "lower",
"color-hex-length": "long",
"custom-property-empty-line-before": null,
"declaration-empty-line-before": "never",
"function-name-case": [
"lower",
{
"ignoreFunctions": "/^[a-z_](|[a-zA-Z0-9]+)$/"
}
],
"keyframes-name-pattern": "^[a-z][a-zA-Z0-9_]+$",
"max-nesting-depth": 6,
"no-descending-specificity": null,
"no-invalid-position-at-import-rule": null,
"number-leading-zero": "always",
"property-no-vendor-prefix": [
true,
{
"ignoreProperties": ["appearance"]
}
],
"scale-unlimited/declaration-strict-value": [
"color",
{
"ignoreValues": ["inherit", "initial"]
}
],
"scss/at-function-pattern": "^[a-z_](|[a-zA-Z0-9-]+)$",
"scss/at-mixin-pattern": "^[a-z_](|[a-zA-Z0-9]+)$",
"scss/dollar-variable-empty-line-before": null,
"scss/dollar-variable-pattern": [
"^[A-Z0-9_]+$",
{
"ignore": "local"
}
],
"scss/double-slash-comment-empty-line-before": null,
"selector-max-id": 0,
"selector-class-pattern": "^[a-z](|[a-zA-Z0-9]+)$",
"selector-pseudo-class-no-unknown": [
true,
{
"ignorePseudoClasses": ["global"]
}
],
"string-quotes": "single"
}
}
todoList 기본 구조
<div className={styles.todoList}>
<div className={styles.centering}>
<h1>Hi! this is your assignment.</h1>
<ul className={styles.tasks}>
<p className={styles.tasksTitle}>Today's</p>
{todoList.map((todo) => (
<li key={`todo-${todo.id}`} className={styles.task}>
<div className={styles.checkboxWrapper}>
<input type='checkbox' checked={todo.done} data-id={todo.id} onChange={handleChange} />
<CheckIcon />
</div>
<p className={styles.title}>{todo.title}</p>
</li>
))}
</ul>
<button type='button' className={styles.addButton} onClick={handleAddClick} aria-label='Add button' />
</div>
</div>
styles.todoList
투두리스트의 가장 바깥을 감싸는 태그
styles.centering
가운데 정렬을 맞추기 위한 태그
h1
최상단 타이틀
이미지상에서는 “What’s up, [사용자명]!”
이 들어간다
ul
투두가 리스트 형태로 여러 개 들어가기 때문에, ul
과 li
태그를 사용하여 리스트로 구성한다
li
각각의 투두 컴포넌트
styles.checboxWrapper
투두 컴포넌트 왼쪽의 체크박스를 감싸는 태그
체크박스 위에 체크 아이콘이 올라가야 하므로 position: relative
를 적용한 wrapper
로 감싸준다
input type=’checkbox’
각각의 투두 컴포넌트 왼쪽에 위치한 체크박스
투두 완료 여부를 체크한다
CheckIcon
✔️ 체크 아이콘 (svg)
p
투두 컴포넌트의 제목 (할 일)
Pay for rent
같은 게 들어가는 부분
button
우측 하단의 투두를 추가할 수 있는 페이지가 나오는 아이콘
스타일 적용하기
개발자 도구에서 미리보기
개발자 도구의 Styles 탭에서 임의로 css 스타일을 추가하면 파일에 추가하기 전에 브라우저에서 미리 적용된 모습을 확인가능하다
매번 파일 수정하고 저장하고 미리보기 하지 말고 한번 개발자도구에 넣어보고 적용해보자
CSS에서 input type 구분하기 (타입 선택자)
input[type=checkbox] {
//
&:checked {
// 체크되었을 때 선택자
}
}
체크박스 타입의 input
에만 스타일이 적용된다
체크박스가 체크되었을 때 스타일은 선택자 :checked
를 이용한다
색상 지정 시 rgb() 는 레거시 코드
rgb(R G B / 투명도) // 투명도는 0 ~ 1 사이
stylelint에서 권장하지 않는 레거시 코드이니
rgba(R, G, B, 투명도) // 투명도는 0 ~ 100% 사이
rgba
를 사용하자
position mixin
@use '/src/styles/mixins/position'
...
@include position.middleBox; // 부모 태그의 정중앙에 배치하는 mixin
position
속성 관련 사전 설정이 들어있는 mixin으로, 컴포넌트 겹치기 같은 스타일을 적용하고 싶을 때 사용한다
check input과 svg 겹칠 때 주의사항
position: absolute
; 와 z-index
를 이용하여 두 컴포넌트를 앞뒤로 겹치게 되면, 뒤에 있는 컴포넌트가 클릭이 원활히 되지 않는다 (안 겹치는 부분을 클릭해야만 이벤트가 실행됨)
svg
에 pointer-events: none
을 적용하면 해당 svg
는 클릭 이벤트를 받지 않으므로 뒤에 있는 check input
이 정상적으로 클릭된다
::before, ::after 선택자를 사용한 예
.addButton {
@include position.absolute(auto 40px 40px auto);
width: 66px;
height: 66px;
background-color: colors.$BLUE;
border-radius: 50%;
box-shadow: 0 10px 20px 0 rgba(colors.$BLACK, 15%);
transition: 0.2s;
&::before,
&::after {
@include position.middleBox;
width: 20px;
height: 2px;
content: '';
background-color: colors.$WHITE;
}
...
&::after {
transform: translate(-50%, -50%) rotate(90deg);
transform-origin: center;
}
}
addButton
을 66*66px
의 동그란 파란색 버튼으로 만들어준 후, ::before
과 ::after
선택자를 이용하여 내부 내용물인 플러스 막대기를 만들어주었다
::before
, ::after
모두 css 스타일을 적용받으므로 이를 이용하여 가로세로 길이를 정하고 position
Mixin을 통해 버튼의 앞에 배치하였으며, ::after
선택자의 내용물만 90도 회전시켜 + 기호처럼 보이도록 하였다
추가적인 태그 요소를 내부에 배치할 필요 없이 CSS만으로 태그 요소처럼 작성할 수 있는 것 (쩐다)
transform-origin
은 요소를 회전시킬 때 중심점을 지정하는 태그이다
글자 오버플로우 막기
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap
- 요소 안의 텍스트가 요소의 너비를 넘어서버릴 경우 (overflow), 화이트스페이스 (공백, 개행, 탭 등) 를 기준으로 개행을 넣어 다음 줄로 옮길지 말지 결정하는 속성
nowrap
은 자동으로 다음 줄로 넘어가지 않게 한다 (개행을 넣지 않는다)
text-overflow: ellipsis
- 요소 안의 텍스트가 요소의 너비를 넘어서버릴 경우 (overflow), 넘어간 텍스트를 어떻게 처리할 지 결정하는 속성
overflow
속성과 같이 사용한다ellipsis
는 빠져나간 텍스트를...
으로 대체해준다
overflow: hidden
- 요소 안의 내용물이 (텍스트이든 자식 요소든) 요소의 너비를 넘어서버릴 경우 (overflow), 넘어간 내용물의 모습을 결정하는 속성
hidden
속성은 요소의 너비를 넘어간 부분을 가려버린다scroll
속성으로 스크롤을 지정할 수도 있다
이벤트로 data 받아오기
const [id, setID] = useState(0);
const handleChange = (e) => {
console.log(e.currentTarget.dataset);
}
...
<input
type='checkbox'
...
data-id={todo.id}
onChange={handleChange}
/>
data-[데이터 key이름]
이런 식으로 props
를 설정하면, 이벤트 객체의 dataset
항목으로 받아올 수 있다
<input
type='checkbox'
...
data-id={todo.id}
data-test="aaa"
onChange={handleChange}
/>
예를 들어 input이 이렇게 이루어져 있다면, e.currentTarget.dataset
에서 key가 id
인 값과 test
인 값 2개를 받아올 수 있는 것
구조분해 할당을 통해 값을 받아와 사용하자
'프로젝트 > 원티드 프리온보딩' 카테고리의 다른 글
[프리온보딩] 220509 개인과제 #1 시작 (0) | 2022.05.10 |
---|---|
[프리온보딩] 220508 강의 메모 01 (그룹과제 코드리뷰) (0) | 2022.05.10 |
[프리온보딩] 220508 그룹과제 #1 끝 (0) | 2022.05.09 |
[프리온보딩] 220507 내 과제 리팩토링 2 (0) | 2022.05.08 |
[프리온보딩] 220506 내 과제 리팩토링 (0) | 2022.05.07 |