├── public ├── favicon.ico ├── fonts │ └── PretendardVariable.woff2 └── vercel.svg ├── .vscode ├── extensions.json └── settings.json ├── src ├── components │ ├── forms │ │ ├── index.ts │ │ ├── Input.tsx │ │ ├── FormField.tsx │ │ └── InputContainer.tsx │ ├── buttons │ │ ├── index.ts │ │ ├── PrimaryButton.tsx │ │ └── SolidButton.tsx │ └── Loading.tsx ├── pages │ ├── _app.tsx │ └── index.tsx ├── styles │ ├── fonts.css │ ├── getGlobalStyles.tsx │ └── Colors.ts └── utils │ └── ColorScheme.ts ├── README.md ├── next.config.js ├── .gitignore ├── tsconfig.json ├── package.json ├── .eslintrc.json └── yarn.lock /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indentcorp/bizmsg-devtools/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/components/forms/index.ts: -------------------------------------------------------------------------------- 1 | export { FormField } from './FormField' 2 | export { Input } from './Input' 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 비즈엠 Devtools 2 | 3 | 비즈엠 개발 서버에서 전화번호 인증을 쉽게 할 수 있는 웹사이트입니다. 4 | 5 | https://bizmsg-devtools.vercel.app 6 | -------------------------------------------------------------------------------- /src/components/buttons/index.ts: -------------------------------------------------------------------------------- 1 | export { PrimaryButton } from './PrimaryButton' 2 | export { SolidButton } from './SolidButton' 3 | -------------------------------------------------------------------------------- /public/fonts/PretendardVariable.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indentcorp/bizmsg-devtools/HEAD/public/fonts/PretendardVariable.woff2 -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | compiler: { 6 | emotion: true, 7 | }, 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[javascript]": { 3 | "editor.formatOnSave": true, 4 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 5 | }, 6 | "[typescript]": { 7 | "editor.formatOnSave": true, 8 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 9 | }, 10 | "[typescriptreact]": { 11 | "editor.formatOnSave": true, 12 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 13 | }, 14 | "eslint.format.enable": true 15 | } 16 | -------------------------------------------------------------------------------- /src/components/buttons/PrimaryButton.tsx: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | import { SolidButton } from './SolidButton' 4 | 5 | import { AbsoluteColors } from '@/styles/Colors' 6 | 7 | export const PrimaryButton = styled(SolidButton)` 8 | background-color: ${AbsoluteColors.blue500}; 9 | 10 | &:hover { 11 | background-color: ${AbsoluteColors.blue600}; 12 | } 13 | 14 | &:active { 15 | background-color: ${AbsoluteColors.blue800}; 16 | } 17 | ` 18 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { Global } from '@emotion/react' 2 | import type { AppProps } from 'next/app' 3 | 4 | import { getGlobalStyles } from '@/styles/getGlobalStyles' 5 | import { useColorScheme } from '@/utils/ColorScheme' 6 | 7 | function MyApp({ Component, pageProps }: AppProps) { 8 | const colorScheme = useColorScheme() 9 | return <> 10 | 11 | 12 | 13 | } 14 | 15 | export default MyApp 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /src/styles/fonts.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Kil Hyung-jin, with Reserved Font Name Pretendard. 3 | https://github.com/orioncactus/pretendard 4 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 5 | This license is copied below, and is also available with a FAQ at: 6 | http://scripts.sil.org/OFL 7 | */ 8 | 9 | @font-face { 10 | font-family: 'Pretendard Variable'; 11 | font-weight: 45 920; 12 | font-style: normal; 13 | font-display: swap; 14 | src: local('Pretendard Variable'), url('/fonts/PretendardVariable.woff2') format('woff2-variations'); 15 | } 16 | -------------------------------------------------------------------------------- /src/components/forms/Input.tsx: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | import React from 'react' 3 | 4 | import { InputContainer, InputContainerProps } from './InputContainer' 5 | 6 | export type InputProps = React.InputHTMLAttributes & InputContainerProps 7 | 8 | export const _Input = (props: InputProps, ref: React.Ref) => { 9 | return ( 10 | 11 | 12 | 13 | ) 14 | } 15 | 16 | export const Input = React.forwardRef(_Input) 17 | 18 | const InputBase = styled.input` 19 | height: 48px; 20 | ` 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "baseUrl": "src", 18 | "paths": { 19 | "@/assets/*": ["../public/assets/*"], 20 | "@/*": ["*"] 21 | }, 22 | }, 23 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 24 | "exclude": ["node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bizmsg-devtools", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@emotion/react": "^11.10.4", 13 | "@emotion/styled": "^11.10.4", 14 | "axios": "^0.27.2", 15 | "next": "12.3.0", 16 | "polished": "^4.2.2", 17 | "react": "18.2.0", 18 | "react-dom": "18.2.0" 19 | }, 20 | "devDependencies": { 21 | "@types/node": "18.7.18", 22 | "@types/react": "18.0.20", 23 | "@types/react-dom": "18.0.6", 24 | "@typescript-eslint/eslint-plugin": "^5.37.0", 25 | "@typescript-eslint/parser": "^5.37.0", 26 | "eslint": "8.23.1", 27 | "eslint-config-next": "12.3.0", 28 | "eslint-plugin-import": "^2.26.0", 29 | "typescript": "4.8.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/forms/FormField.tsx: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | import { CSSProperties } from 'react' 3 | 4 | import { RelativeColors } from '@/styles/Colors' 5 | 6 | export type FormFieldProps = { 7 | className?: string, 8 | style?: CSSProperties, 9 | label?: string, 10 | children?: React.ReactNode 11 | } 12 | 13 | export const FormField = (props: FormFieldProps) => { 14 | return ( 15 | 16 | {props.label && ( 17 | 18 | )} 19 | {props.children} 20 | 21 | ) 22 | } 23 | 24 | const Container = styled.div` 25 | display: flex; 26 | flex-direction: column; 27 | align-items: stretch; 28 | ` 29 | 30 | const Label = styled.label` 31 | margin-bottom: 10px; 32 | font-weight: normal; 33 | font-size: 16px; 34 | line-height: 19px; 35 | letter-spacing: -0.02em; 36 | color: ${RelativeColors.gray900}; 37 | ` 38 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /src/styles/getGlobalStyles.tsx: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react' 2 | 3 | import { RelativeColors, SemanticColors } from './Colors' 4 | 5 | import { ColorScheme } from '@/utils/ColorScheme' 6 | 7 | type Options = { 8 | colorScheme: ColorScheme | undefined, 9 | } 10 | 11 | export const getGlobalStyles = ({ colorScheme }: Options) => css` 12 | html, 13 | body { 14 | padding: 0; 15 | margin: 0; 16 | font-family: 'Pretendard Variable', -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 17 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 18 | } 19 | 20 | body { 21 | background-color: ${SemanticColors.background('light')}; 22 | } 23 | 24 | @media (prefers-color-scheme: dark) { 25 | :root { 26 | color-scheme: dark; 27 | } 28 | 29 | body { 30 | background-color: ${SemanticColors.background('dark')}; 31 | } 32 | } 33 | 34 | * { 35 | box-sizing: border-box; 36 | padding: 0; 37 | margin: 0; 38 | } 39 | 40 | a { 41 | color: ${RelativeColors.blue500(colorScheme)}; 42 | text-decoration: none; 43 | } 44 | 45 | ul, li { 46 | margin: 0; 47 | padding: 0; 48 | list-style-type: none; 49 | } 50 | 51 | button { 52 | border: 0; 53 | cursor: pointer; 54 | 55 | &:focus { 56 | outline: 0; 57 | } 58 | } 59 | ` 60 | -------------------------------------------------------------------------------- /src/utils/ColorScheme.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useState } from 'react' 2 | 3 | export type ColorScheme = 'light' | 'dark'; 4 | 5 | const MEDIA_QUERY = '(prefers-color-scheme: dark)' 6 | 7 | export const getColorScheme = (): ColorScheme | undefined => { 8 | if (typeof window === 'undefined') { 9 | return 'light' 10 | } 11 | return window.matchMedia(MEDIA_QUERY).matches ? 'dark' : 'light' 12 | } 13 | 14 | let currentColorScheme: ColorScheme | undefined 15 | 16 | export const getCurrentColorScheme = (): ColorScheme | undefined => { 17 | return currentColorScheme 18 | } 19 | 20 | export const useColorScheme = (): ColorScheme | undefined => { 21 | const [colorScheme, _setColorScheme] = useState(undefined) 22 | const setColorScheme = useCallback((newColorScheme: ColorScheme | undefined) => { 23 | _setColorScheme(newColorScheme) 24 | currentColorScheme = newColorScheme 25 | }, []) 26 | 27 | useEffect(() => { 28 | setColorScheme(getColorScheme()) 29 | }, [setColorScheme]) 30 | 31 | const onMatchMediaChange = useCallback((event: MediaQueryListEvent) => { 32 | setColorScheme(event.matches ? 'dark' : 'light') 33 | }, [setColorScheme]) 34 | 35 | useEffect(() => { 36 | const metchMedia = window.matchMedia(MEDIA_QUERY) 37 | metchMedia.addEventListener('change', onMatchMediaChange) 38 | return () => metchMedia.removeEventListener('change', onMatchMediaChange) 39 | }, [onMatchMediaChange]) 40 | 41 | return colorScheme 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/components/buttons/SolidButton.tsx: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | import React from 'react' 3 | 4 | import { Loading } from '@/components/Loading' 5 | import { AbsoluteColors, RelativeColors } from '@/styles/Colors' 6 | 7 | export type SolidButtonProps = React.ButtonHTMLAttributes & { 8 | loading?: boolean 9 | } 10 | 11 | const SolidButtonBase = (props: SolidButtonProps, ref: React.Ref) => { 12 | const buttonProps = { 13 | ...props, 14 | isLoading: props.loading, 15 | children: !props.loading 16 | ? props.children 17 | : , 18 | } 19 | 20 | // https://github.com/styled-components/styled-components/issues/3090 21 | delete buttonProps.loading 22 | 23 | return