New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[항공사 웹사이트의 컴포넌트 접근성 높이기 - 1단계] 비녀(강윤호) 미션 제출합니다. #52
Changes from all commits
3ce7817
6cb5a1d
f36bbf5
135b2c0
a5eed63
b163a75
5860280
ea32fdb
9bd2bc6
e08e0d9
cabdd88
682e7ed
5ba6b3f
c95c8b6
08fddb6
5fcfaec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"name": "a11y-airline", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
"repository": "https://github.com/KangYunHo1221/a11y-airline", | ||
"author": "Yunho <ansghkdbsgh@gmail.com>", | ||
"license": "MIT", | ||
"scripts": { | ||
"start": "webpack serve --open", | ||
"build": "webpack --mode=production", | ||
"deploy": "gh-pages -d dist" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^18.8.2", | ||
"@types/react": "^18.0.21", | ||
"@types/react-dom": "^18.0.6", | ||
"css-loader": "^6.7.1", | ||
"html-webpack-plugin": "^5.5.0", | ||
"mini-css-extract-plugin": "^2.6.1", | ||
"ts-loader": "^9.4.1", | ||
"typescript": "^4.8.4", | ||
"webpack": "^5.74.0", | ||
"webpack-cli": "^4.10.0", | ||
"webpack-dev-server": "^4.11.1", | ||
"gh-pages": "^4.0.0" | ||
}, | ||
"dependencies": { | ||
"@types/styled-components": "^5.1.26", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"react-router-dom": "^6.4.1", | ||
"styled-components": "^5.3.6" | ||
}, | ||
"homepage": "." | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!DOCTYPE html> | ||
<html lang="ko"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width,initial-scale=1" /> | ||
<meta name="keyword" content="미션, 항공사, 웹사이트, 접근성" /> | ||
<meta name="description" content="미션: 항공사 웹사이트 컴포넌트의 접근성 높이기" /> | ||
<meta property="og:type" content="website" /> | ||
<meta property="og:url" content="https://capable-pixie-ad7eb2.netlify.app/" /> | ||
<meta property="og:title" content="a11y-airline" /> | ||
<meta property="og:description" content="미션: 항공사 웹사이트 컴포넌트의 접근성 높이기" /> | ||
<title>웹 접근성 미션</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { BrowserRouter, Route, Routes } from 'react-router-dom'; | ||
import FirstPage from './pages/FirstPage'; | ||
|
||
const App = () => { | ||
return ( | ||
<BrowserRouter> | ||
<Routes> | ||
<Route path='/' element={<FirstPage />} /> | ||
</Routes> | ||
</BrowserRouter> | ||
); | ||
}; | ||
|
||
export default App; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { useState } from 'react'; | ||
import styled from 'styled-components'; | ||
import Tooltip from '../components/Tooltip'; | ||
|
||
const FirstPage = () => { | ||
const [count, setCount] = useState<number>(1); | ||
|
||
const countUp = () => { | ||
setCount((prev) => { | ||
if (prev + 1 <= 3) { | ||
return prev + 1; | ||
} | ||
return prev; | ||
}); | ||
}; | ||
|
||
const countDown = () => { | ||
setCount((prev) => { | ||
if (prev - 1 >= 1) { | ||
return prev - 1; | ||
} | ||
return prev; | ||
}); | ||
}; | ||
|
||
const handleCountChange = (e: React.KeyboardEvent<HTMLInputElement>) => { | ||
const input = Number(e.key); | ||
|
||
if (input >= 1 && input <= 3) { | ||
setCount(input); | ||
} | ||
}; | ||
|
||
const makeText = () => { | ||
const text = `성인 승객이 ${count}으로 변경됐습니다`; | ||
return text; | ||
}; | ||
return ( | ||
<S.PageWrapper> | ||
<h1>승객 선택</h1> | ||
<S.SubtitleWrapper> | ||
<h2>성인</h2> | ||
<Tooltip /> | ||
</S.SubtitleWrapper> | ||
<S.ControlWrapper> | ||
<S.Button aria-label='성인 탑승자 한명 줄이기' onClick={countDown}> | ||
- | ||
</S.Button> | ||
<S.Count | ||
type='number' | ||
min={1} | ||
max={3} | ||
onKeyDown={(e) => { | ||
handleCountChange(e); | ||
}} | ||
value={count} | ||
/> | ||
<S.Button aria-label='성인 탑승자 한명 늘리기' onClick={countUp}> | ||
+ | ||
</S.Button> | ||
<S.HiddenText>{makeText()}</S.HiddenText> | ||
</S.ControlWrapper> | ||
</S.PageWrapper> | ||
); | ||
}; | ||
|
||
const S = { | ||
PageWrapper: styled.div` | ||
height: 300px; | ||
width: 250px; | ||
border: 2px solid gray; | ||
display: flex; | ||
flex-direction: column; | ||
gap: 20px; | ||
align-items: center; | ||
`, | ||
SubtitleWrapper: styled.div` | ||
position: relative; | ||
display: flex; | ||
align-items: center; | ||
gap: 4px; | ||
`, | ||
Button: styled.button` | ||
width: 30px; | ||
height: 30px; | ||
border: 1px solid #b8b8b8; | ||
border-radius: 50%; | ||
font-size: 22px; | ||
background-color: transparent; | ||
cursor: pointer; | ||
`, | ||
Count: styled.input` | ||
width: 32px; | ||
text-align: center; | ||
font-size: 24px; | ||
border: none; | ||
border-bottom: 2px solid #6d6d6d; | ||
outline: none; | ||
|
||
::-webkit-outer-spin-button, | ||
::-webkit-inner-spin-button { | ||
-webkit-appearance: none; | ||
margin: 0; | ||
} | ||
`, | ||
ControlWrapper: styled.div` | ||
display: flex; | ||
align-items: center; | ||
gap: 10px; | ||
`, | ||
HiddenText: styled.div.attrs({ role: 'status', 'aria-live': 'assertive', 'aria-relevant': 'additions' })` | ||
position: absolute; | ||
text-indent: -9999px; | ||
`, | ||
}; | ||
|
||
export default FirstPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import styled from 'styled-components'; | ||
|
||
const Tooltip = () => { | ||
return ( | ||
<> | ||
<S.Question aria-label='tooltip'>?</S.Question> | ||
<S.StyledTooltip aria-live='assertive' id='tooltip' role='tooltip'> | ||
국민은행 61210204071715로 후원해 결식아동을 도와보세요! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 큰일납니다. 👮♂️ |
||
</S.StyledTooltip> | ||
</> | ||
); | ||
}; | ||
|
||
const S = { | ||
Question: styled.button` | ||
width: 20px; | ||
height: 20px; | ||
border: 1px solid #cbcbcb; | ||
color: #cbcbcb; | ||
border-radius: 50%; | ||
text-align: center; | ||
cursor: help; | ||
background-color: white; | ||
|
||
&:hover + [role='tooltip'], | ||
&:focus + [role='tooltip'] { | ||
display: block !important; | ||
background-color: red; | ||
} | ||
`, | ||
StyledTooltip: styled.div` | ||
display: ${(props) => (props.role === 'tooltip' ? 'none' : 'block')}; | ||
|
||
position: absolute; | ||
top: -3rem; | ||
left: 4rem; | ||
padding: 4px; | ||
color: white; | ||
`, | ||
}; | ||
|
||
export default Tooltip; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { createRoot } from 'react-dom/client'; | ||
import App from './App'; | ||
|
||
const container = document.getElementById('root')!; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 뒤에 !는 처음보는데 뭐하는 건가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 무조건 null이나 undefined 아니라는 뜻입니다.
|
||
const root = createRoot(container); | ||
|
||
root.render(<App />); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"compileOnSave": true, | ||
"compilerOptions": { | ||
"target": "es6", | ||
"module": "esnext", | ||
"strict": true, | ||
"allowJs": true, | ||
"lib": ["dom", "dom.iterable", "esnext"], | ||
"jsx": "react-jsx", | ||
"skipLibCheck": true, | ||
"incremental": true, | ||
"moduleResolution": "node" | ||
}, | ||
"include": ["src/**/*"], | ||
"exclude": ["node_modules"] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
const path = require('path'); | ||
const HtmlWebpackPlugin = require('html-webpack-plugin'); | ||
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); | ||
|
||
module.exports = { | ||
entry: './src/index.tsx', | ||
devServer: { | ||
compress: true, | ||
port: 3000, | ||
}, | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.tsx?$/, | ||
use: [{ loader: 'ts-loader' }], | ||
exclude: /node_modules/, | ||
}, | ||
{ | ||
test: /\.module.css$/, | ||
use: [MiniCssExtractPlugin.loader, 'css-loader'], | ||
}, | ||
], | ||
}, | ||
resolve: { | ||
extensions: ['.tsx', '.ts', '.js'], | ||
}, | ||
output: { | ||
filename: 'bundle[hash].js', | ||
clean: true, | ||
path: path.resolve(__dirname, 'dist'), | ||
}, | ||
mode: 'production', | ||
plugins: [new HtmlWebpackPlugin({ template: './public/index.html' }), new MiniCssExtractPlugin()], | ||
performance: { hints: false }, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 속성을 추가했을 때와 하지 않았을 때 동작이 동작이 똑같은데 추가하신 이유가 있나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
min max를 추가해주면 스크린 리더가 읽어줄때 min max를 알려줍니다.
js로도 제한이 가능하지만 명시해주는게 더 시맨틱하다고 판단했습니다