diff --git a/package.json b/package.json index c356ea8..0611333 100644 --- a/package.json +++ b/package.json @@ -11,5 +11,14 @@ "TS" ], "author": "indiflex", - "license": "ISC" + "license": "ISC", + "devDependencies": { + "prettier": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.6", + "tailwindcss": "^3.4.10" + }, + "dependencies": { + "@types/node": "^22.5.4", + "package.json": "^2.0.1" + } } diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/assets/images/kakao.png" "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/kakao.png" new file mode 100644 index 0000000..5a7ae79 Binary files /dev/null and "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/kakao.png" differ diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/assets/images/naver.png" "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/naver.png" new file mode 100644 index 0000000..c46a3a7 Binary files /dev/null and "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/naver.png" differ diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/assets/images/next.js.svg" "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/next.js.svg" new file mode 100644 index 0000000..5037097 --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/next.js.svg" @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/assets/images/onion.jpg" "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/onion.jpg" new file mode 100644 index 0000000..1eecb94 Binary files /dev/null and "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/onion.jpg" differ diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/assets/images/tailwind-css.svg" "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/tailwind-css.svg" new file mode 100644 index 0000000..c7b4103 --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/tailwind-css.svg" @@ -0,0 +1,32 @@ + + + + + + + diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/assets/images/youtube.svg" "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/youtube.svg" new file mode 100644 index 0000000..d3fd48e --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/assets/images/youtube.svg" @@ -0,0 +1 @@ + \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/book-edit.html" "b/\354\236\204\354\210\230\354\247\204/ex1/book-edit.html" deleted file mode 100644 index e69de29..0000000 diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/index.html" "b/\354\236\204\354\210\230\354\247\204/ex1/index.html" deleted file mode 100644 index e69de29..0000000 diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/register.html" "b/\354\236\204\354\210\230\354\247\204/ex1/register.html" deleted file mode 100644 index e69de29..0000000 diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/src/book-edit.html" "b/\354\236\204\354\210\230\354\247\204/ex1/src/book-edit.html" new file mode 100644 index 0000000..d42e5b1 --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/src/book-edit.html" @@ -0,0 +1,94 @@ + + + + + + + 북마크 편집 + + + + + + + +
+ +
+ +
+ +
+ + +
+ + +
+ + +
+ + +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/src/index.html" "b/\354\236\204\354\210\230\354\247\204/ex1/src/index.html" new file mode 100644 index 0000000..5ed3167 --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/src/index.html" @@ -0,0 +1,153 @@ + + + + + + + 북마크 편집 + + + + + + +
+ +
+

BookMark

+ + +
+ +
+
+ image +
+

My BookMark

+

나만의 북마크를 만들어 보세요 :)

+
+
+
+ +
+
+ + +
+
+ naver +
+

네이버

+

네이버 메인에서 다양한 정보와 유용한 컨텐츠를 만나 보세요

+
+
+
+ +
+
+ + + +
+
+ kakao +
+

Kakao

+

기술과 사람으로 더 나은 세상을 만듭니다.

+
+
+
+ +
+
+ + + +
+
+ youtube +
+

Youtube

+

YouTube에서 마음에 드는 동영상과 음악을 감상하고, 직접 만든 콘텐츠를 업로드하여 친구, 가족뿐 아니라 전 세계 사람들과 공유할 수 있습니다.

+
+
+
+ +
+
+
+ + +
+ +
+
+ + +
+

Study

+ + +
+ +
+
+ tailwind +
+

Tailwind CSS

+

Tailwind CSS is a utility-first CSS framework for rapidly building modern websites without ever leaving your HTML.

+
+
+
+ +
+
+ + +
+
+ nextjs +
+

Create Next App

+

Generated by create next app

+
+
+
+ +
+
+ +
+ + +
+ +
+
+
+ + + + \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/src/input.css" "b/\354\236\204\354\210\230\354\247\204/ex1/src/input.css" new file mode 100644 index 0000000..bd6213e --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/src/input.css" @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/src/output.css" "b/\354\236\204\354\210\230\354\247\204/ex1/src/output.css" new file mode 100644 index 0000000..9c0d472 --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/src/output.css" @@ -0,0 +1,1185 @@ +/* +! tailwindcss v3.4.10 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + letter-spacing: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +.container { + width: 100%; +} + +@media (min-width: 640px) { + .container { + max-width: 640px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 768px; + } +} + +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } +} + +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } +} + +.fixed { + position: fixed; +} + +.absolute { + position: absolute; +} + +.relative { + position: relative; +} + +.inset-x-0 { + left: 0px; + right: 0px; +} + +.top-0 { + top: 0px; +} + +.z-50 { + z-index: 50; +} + +.-m-1\.5 { + margin: -0.375rem; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.mb-10 { + margin-bottom: 2.5rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.mb-8 { + margin-bottom: 2rem; +} + +.ml-4 { + margin-left: 1rem; +} + +.ml-6 { + margin-left: 1.5rem; +} + +.mr-10 { + margin-right: 2.5rem; +} + +.mr-2 { + margin-right: 0.5rem; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mt-20 { + margin-top: 5rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.mt-5 { + margin-top: 1.25rem; +} + +.mt-10 { + margin-top: 2.5rem; +} + +.mb-5 { + margin-bottom: 1.25rem; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.block { + display: block; +} + +.flex { + display: flex; +} + +.h-10 { + height: 2.5rem; +} + +.h-20 { + height: 5rem; +} + +.h-5 { + height: 1.25rem; +} + +.h-8 { + height: 2rem; +} + +.h-screen { + height: 100vh; +} + +.max-h-screen { + max-height: 100vh; +} + +.max-h-10 { + max-height: 2.5rem; +} + +.min-h-screen { + min-height: 100vh; +} + +.w-1\/2 { + width: 50%; +} + +.w-10 { + width: 2.5rem; +} + +.w-20 { + width: 5rem; +} + +.w-8 { + width: 2rem; +} + +.w-full { + width: 100%; +} + +.w-max { + width: -moz-max-content; + width: max-content; +} + +.w-11\/12 { + width: 91.666667%; +} + +.w-1\/12 { + width: 8.333333%; +} + +.max-w-md { + max-width: 28rem; +} + +.max-w-xs { + max-width: 20rem; +} + +.max-w-full { + max-width: 100%; +} + +.max-w-52 { + max-width: 13rem; +} + +.max-w-screen-xl { + max-width: 1280px; +} + +.max-w-screen-lg { + max-width: 1024px; +} + +.flex-1 { + flex: 1 1 0%; +} + +.flex-col { + flex-direction: column; +} + +.items-start { + align-items: flex-start; +} + +.items-center { + align-items: center; +} + +.justify-end { + justify-content: flex-end; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.justify-around { + justify-content: space-around; +} + +.space-x-10 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(2.5rem * var(--tw-space-x-reverse)); + margin-left: calc(2.5rem * calc(1 - var(--tw-space-x-reverse))); +} + +.space-x-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); +} + +.space-x-6 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1.5rem * var(--tw-space-x-reverse)); + margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); +} + +.space-y-6 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); +} + +.overflow-hidden { + overflow: hidden; +} + +.overflow-x-auto { + overflow-x: auto; +} + +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.rounded { + border-radius: 0.25rem; +} + +.rounded-full { + border-radius: 9999px; +} + +.rounded-lg { + border-radius: 0.5rem; +} + +.rounded-md { + border-radius: 0.375rem; +} + +.rounded-sm { + border-radius: 0.125rem; +} + +.border-0 { + border-width: 0px; +} + +.border-l-2 { + border-left-width: 2px; +} + +.border-t { + border-top-width: 1px; +} + +.border-black { + --tw-border-opacity: 1; + border-color: rgb(0 0 0 / var(--tw-border-opacity)); +} + +.border-gray-200 { + --tw-border-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-border-opacity)); +} + +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + +.bg-gray-100 { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.p-1\.5 { + padding: 0.375rem; +} + +.p-2 { + padding: 0.5rem; +} + +.p-4 { + padding: 1rem; +} + +.p-6 { + padding: 1.5rem; +} + +.px-10 { + padding-left: 2.5rem; + padding-right: 2.5rem; +} + +.px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; +} + +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.py-1\.5 { + padding-top: 0.375rem; + padding-bottom: 0.375rem; +} + +.py-10 { + padding-top: 2.5rem; + padding-bottom: 2.5rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.py-2\.5 { + padding-top: 0.625rem; + padding-bottom: 0.625rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.pl-1 { + padding-left: 0.25rem; +} + +.pl-4 { + padding-left: 1rem; +} + +.pl-6 { + padding-left: 1.5rem; +} + +.pr-10 { + padding-right: 2.5rem; +} + +.pr-20 { + padding-right: 5rem; +} + +.pt-24 { + padding-top: 6rem; +} + +.pr-4 { + padding-right: 1rem; +} + +.text-center { + text-align: center; +} + +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + +.font-bold { + font-weight: 700; +} + +.font-extrabold { + font-weight: 800; +} + +.font-medium { + font-weight: 500; +} + +.font-semibold { + font-weight: 600; +} + +.leading-6 { + line-height: 1.5rem; +} + +.tracking-tight { + letter-spacing: -0.025em; +} + +.text-black { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); +} + +.text-blue-400 { + --tw-text-opacity: 1; + color: rgb(96 165 250 / var(--tw-text-opacity)); +} + +.text-blue-600 { + --tw-text-opacity: 1; + color: rgb(37 99 235 / var(--tw-text-opacity)); +} + +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.text-gray-950 { + --tw-text-opacity: 1; + color: rgb(3 7 18 / var(--tw-text-opacity)); +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.shadow { + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-md { + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-sm { + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.ring-1 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.ring-inset { + --tw-ring-inset: inset; +} + +.ring-gray-300 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity)); +} + +.placeholder\:text-gray-400::-moz-placeholder { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.placeholder\:text-gray-400::placeholder { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.hover\:bg-blue-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); +} + +.hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.hover\:underline:hover { + text-decoration-line: underline; +} + +.focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-inset:focus { + --tw-ring-inset: inset; +} + +.focus-visible\:outline:focus-visible { + outline-style: solid; +} + +.focus-visible\:outline-2:focus-visible { + outline-width: 2px; +} + +.focus-visible\:outline-offset-2:focus-visible { + outline-offset: 2px; +} + +@media (min-width: 640px) { + .sm\:mx-auto { + margin-left: auto; + margin-right: auto; + } + + .sm\:w-full { + width: 100%; + } + + .sm\:max-w-sm { + max-width: 24rem; + } + + .sm\:text-5xl { + font-size: 3rem; + line-height: 1; + } + + .sm\:text-sm { + font-size: 0.875rem; + line-height: 1.25rem; + } + + .sm\:leading-6 { + line-height: 1.5rem; + } +} + +@media (min-width: 1024px) { + .lg\:px-8 { + padding-left: 2rem; + padding-right: 2rem; + } +} \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/src/register.html" "b/\354\236\204\354\210\230\354\247\204/ex1/src/register.html" new file mode 100644 index 0000000..661ad62 --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/src/register.html" @@ -0,0 +1,82 @@ + + + + + + + 가입하기 + + + + + + +
+
+
+

Sign up

+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ + +
+ +
+
+
+ + + + + diff --git "a/\354\236\204\354\210\230\354\247\204/ex1/tailwind.config.js" "b/\354\236\204\354\210\230\354\247\204/ex1/tailwind.config.js" new file mode 100644 index 0000000..a0cebb6 --- /dev/null +++ "b/\354\236\204\354\210\230\354\247\204/ex1/tailwind.config.js" @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./src/**/*.{html,js}"], + theme: { + extend: {}, + }, + plugins: [], +} \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex10.test.ts" "b/\354\236\204\354\210\230\354\247\204/ex10.test.ts" index 6218a79..e58144e 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex10.test.ts" +++ "b/\354\236\204\354\210\230\354\247\204/ex10.test.ts" @@ -1,4 +1,54 @@ import { ArrayList } from './ex10'; console.log('🚀 ArrayList:', ArrayList); +import * as assert from 'assert'; -// 여기에 테스트코드를 작성하세요. +// 여기에 테스트코드 +function testArrayList() { + const alist = new ArrayList([1, 2]); + + assert.deepStrictEqual(ArrayList.listToArray({ value: 1, rest: { value: 2, rest: null } }), [1, 2]); + assert.deepStrictEqual(ArrayList.arrayToList([1, 2]), { value: 1, rest: { value: 2, rest: null } }); + + alist.add(3); + assert.deepStrictEqual(alist.toString(), '{ value: 1, rest: { value: 2, rest: { value: 3, rest: null } } }'); + + alist.add(5, 1); + assert.deepStrictEqual(alist.toString(), '{ value: 1, rest: { value: 5, rest: { value: 2, rest: { value: 3, rest: null } } } }'); + + alist.remove(2); + assert.deepStrictEqual(alist.toString(), '{ value: 1, rest: { value: 5, rest: { value: 3, rest: null } } }'); + + alist.add(22, 1); + assert.deepStrictEqual(alist.toString(), '{ value: 1, rest: { value: 22, rest: { value: 5, rest: { value: 3, rest: null } } } }'); + + alist.add(33, 1); + assert.deepStrictEqual(alist.toArray(), [1, 33, 22, 5, 3]); + + assert.deepStrictEqual(alist.toString(), '{ value: 1, rest: { value: 33, rest: { value: 22, rest: { value: 5, rest: { value: 3, rest: null } } } } }'); + + alist.set(1, 300); + alist.get(2); + + assert.strictEqual(alist.get(2), 22); + assert.strictEqual(alist.size(), 5); + assert.strictEqual(alist.indexOf(300), 1); + assert.strictEqual(alist.contains(300), true); + assert.strictEqual(alist.contains(301), false); + assert.strictEqual(alist.isEmpty(), false); + assert.strictEqual(alist.peek(), 1); + + assert.deepStrictEqual(alist.toArray(), [1, 300, 22, 5, 3]); + + const iterator = alist[Symbol.iterator](); + assert.deepStrictEqual(iterator.next(), { value: 1, done: false }); + assert.deepStrictEqual(iterator.next(), { value: 300, done: false }); + assert.deepStrictEqual(iterator.next(), { value: 22, done: false }); + assert.deepStrictEqual(iterator.next(), { value: 5, done: false }); + assert.deepStrictEqual(iterator.next(), { value: 3, done: false }); + assert.deepStrictEqual(iterator.next(), { value: undefined, done: true }); + + alist.clear(); + assert.deepStrictEqual(alist.size(), 0); +} + +testArrayList(); \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex10.ts" "b/\354\236\204\354\210\230\354\247\204/ex10.ts" index 1ffaef5..4002cde 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex10.ts" +++ "b/\354\236\204\354\210\230\354\247\204/ex10.ts" @@ -1,71 +1,224 @@ -class Collection { - private readonly arr = Array(); - - constructor(...args: T[]) { - this.arr.push(...args); +interface ListNode { + value: T; + rest: ListNode | null; } - - get _arr() { - return this.arr; - } - - push(...args: T[]) { - this.arr.push(...args); - return this.arr; - } - - get peek(): T | undefined { - return this.isQueue() ? this.arr[0] : this.arr.at(-1); - } - - get poll(): T | undefined { - return this.isQueue() ? this.arr.shift() : this.arr.pop(); - } - - remove() { - return this.poll; - } - - get length() { - return this.arr.length; - } - - get isEmpty() { - return !this.arr.length; - } - - clear() { - this.arr.length = 0; - } - - iterator() { - return this[Symbol.iterator](); - } - - // [1, 2, 3] - *[Symbol.iterator]() { - for (let i = this.length - 1; i >= 0; i -= 1) { - yield this.toArray()[i]; + + class Collection { + protected items: T[] = []; + + push(...args: T[]): T[] { + this.items.push(...args); + return this.items; + } + + get _arr(): T[] { + return this.items; } } - - toArray() { - return this.isQueue() ? this.arr.toReversed() : this.arr; - } - - print() { - console.log(`<${this.constructor.name}: [${this.toArray()}]>`); - } - - private isQueue() { - return this instanceof Queue; + + class ArrayList extends Collection { + private node: ListNode | null = null; + + constructor(arr: T[] = []) { + super(); + this.push(...arr); + this.node = this.arrayToLinkedNode(this._arr); + } + + public static arrayToList(array: T[]): ListNode | null { + if (array.length === 0) return null; + let result: ListNode = { value: array[0], rest: null }; + let current = result; + for (let i = 1; i < array.length; i++) { + current.rest = { value: array[i], rest: null }; + current = current.rest; + } + return result; + } + + public static listToArray(list: ListNode | null): T[] { + const result: T[] = []; + let current = list; + while (current) { + result.push(current.value); + current = current.rest || null; + } + return result; + } + + arrayToLinkedNode(arr: T[]): ListNode | null { + if (arr.length === 0) return null; + let node: ListNode = { value: arr[0], rest: null }; + let current = node; + for (let i = 1; i < arr.length; i++) { + current.rest = { value: arr[i], rest: null }; + current = current.rest; + } + return node; + } + + add(item: T, index?: number): ListNode { + if (index === undefined) { + let lst = this.node; + if (!lst) { + this.node = { value: item, rest: null }; + return this.node; + } + while (lst.rest !== null) { + lst = lst.rest as ListNode; + } + lst.rest = { value: item, rest: null }; + } else { + if (index < 0) throw new Error('Index must be greater than or equal to 0'); + if (index === 0) { + this.node = { value: item, rest: this.node }; + return this.node; + } + + let current = this.node; + let depth = 0; + while (current?.rest !== null && depth < index - 1) { + if (current) current = current.rest; + + depth++; + } + + if (!current) throw new Error('Index is out of range'); + current.rest = { value: item, rest: current.rest }; + } + return this.node as ListNode; + } + + size(): number { + let current = this.node; + let count = 0; + while (current !== null) { + count++; + current = current.rest; + } + return count; + } + + remove(item: T): ListNode | null { + if (!this.node) return null; + if (this.node.value === item) { + this.node = this.node.rest || null; + return this.node; + } + + let current = this.node; + while (current.rest !== null) { + if (current.rest.value === item) { + current.rest = current.rest.rest; + return this.node; + } + current = current.rest; + } + return this.node; + } + + removeByIndex(index: number): ListNode | null { + if (!this.node) return null; + if (index === 0) { + this.node = this.node.rest || null; + return this.node; + } + + let current = this.node; + let depth = 0; + while (current?.rest !== null && depth < index - 1) { + current = current.rest; + depth++; + } + + if (!current?.rest) throw new Error('Index is out of range'); + current.rest = current.rest.rest; + return this.node; + } + + set(index: number, item: T): ListNode | null { + if (!this.node) throw new Error('Array is empty'); + let current = this.node; + let depth = 0; + while (depth < index) { + if (!current?.rest) throw new Error('Index is out of range'); + current = current.rest; + depth++; + } + current.value = item; + return this.node; + } + + get(index: number): T | undefined { + if (!this.node) return undefined; + let current = this.node; + let depth = 0; + while (depth < index) { + if (!current?.rest) return undefined; + current = current.rest; + depth++; + } + return current?.value; + } + + toArray(): T[] { + return ArrayList.listToArray(this.node); + } + + toString(): string { + const listToString = (node: ListNode | null): string => { + if (!node) return 'null'; + return `{ value: ${node.value}, rest: ${listToString(node.rest || null)} }`; + }; + return listToString(this.node); + } + + clear(): void { + this.node = null; + } + + isEmpty(): boolean { + return this.node === null; + } + + contains(item: T): boolean { + let current = this.node; + while (current) { + if (current.value === item) return true; + current = current.rest; + } + return false; + } + + indexOf(item: T): number | null { + let current = this.node; + let index = 0; + while (current) { + if (current.value === item) return index; + current = current.rest; + index++; + } + return -1; + } + + peek(): T | null { + return this.node?.value || null; + } + + [Symbol.iterator](): Iterator { + let current = this.node; + return { + next(): IteratorResult { + if (!current) { + return { value: undefined, done: true }; + } + let value = current.value; + current = current.rest || null; + return { value, done: false }; + }, + }; + } } -} - -class Stack extends Collection {} -class Queue extends Collection {} - -// ArrayList 클래스를 작성하세요. -class ArrayList extends Collection {} - -export { Stack, Queue, ArrayList }; + + export { ArrayList, Collection }; + \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex2.js" "b/\354\236\204\354\210\230\354\247\204/ex2.js" index 6b95f04..7ca42f5 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex2.js" +++ "b/\354\236\204\354\210\230\354\247\204/ex2.js" @@ -1,4 +1,39 @@ -// range 함수를 작성하세요. -const range = (start, end, step = start > end ? -1 : 1) => { }; +const range = (start, end, step = start > end ? -1 : 1) => { -module.exports = { range }; + const result = []; + const EPSILON = 1e-10; // 부동 소수점 오차를 보정하기 위한 아주 작은 값 + const DECIMALS = 10; // 소수점 자리수 + + if (step === 0 || start === end) return [start]; + + // end가 없을 경우 + if (end === undefined) { + if (start > 0) { + end = start; + start = 1; + } else if (start < 0) { + end = -1; + } else { + // start가 0일 경우 + result.push(start); + } + } + + // 예외 + if ((start - end) * step > 0) return []; + + if (step > 0) { + for (let i = start; i <= end + EPSILON; i += step) { + if (i > end + EPSILON) break; // 범위를 초과할 경우 종료 + result.push(parseFloat(i.toFixed(DECIMALS))); + } + } else { + for (let i = start; i >= end - EPSILON; i += step) { + if (i < end - EPSILON) break; // 범위를 초과할 경우 종료 + result.push(parseFloat(i.toFixed(DECIMALS))); + } + } + return result; +}; + +module.exports = { range }; \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex3.js" "b/\354\236\204\354\210\230\354\247\204/ex3.js" index b1b0d75..76c87f3 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex3.js" +++ "b/\354\236\204\354\210\230\354\247\204/ex3.js" @@ -1,3 +1,17 @@ Array.prototype.sortBy = function (sortProp = '') { - return this; -}; + const sortArray = sortProp.split(','); + + // 각 기준을 [sortKey, order] 형태로 변환 + const sortPairs = sortArray.map(value => { + const [sortKey, order] = value.split(':'); + return [sortKey, order || 'asc']; // order가 비어있을 경우 기본값 'asc'로 설정 + }); + + return this.slice().sort((a, b) => { + for (const [sortKey, order] of sortPairs) { + if (a[sortKey] > b[sortKey]) return order === 'desc' ? -1 : 1; + if (a[sortKey] < b[sortKey]) return order === 'desc' ? 1 : -1; + } + return 0; + }); +}; \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex3.test.js" "b/\354\236\204\354\210\230\354\247\204/ex3.test.js" index 6c27a4d..bc37804 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex3.test.js" +++ "b/\354\236\204\354\210\230\354\247\204/ex3.test.js" @@ -8,11 +8,11 @@ const users = [lee, hong, kim]; assert.deepStrictEqual(users.sortBy('id'), [hong, kim, lee]); assert.deepStrictEqual(users.sortBy('name:desc'), [lee, kim, hong]); -assert.deepStrictEqual(users.sortBy('dept:desc,city:asc'), [hong, lee, kim]); +assert.deepStrictEqual(users.sortBy('dept:desc,city:asc'), [lee, kim, hong]); assert.deepStrictEqual(users.sortBy('dept:desc,city:desc'), [kim, lee, hong]); assert.deepStrictEqual(users.sortBy('name:desc,id:,dept:desc'), [ - kim, lee, + kim, hong, ]); -assert.deepStrictEqual(users.sortBy('dept:desc,id'), [hong, kim, lee]); +assert.deepStrictEqual(users.sortBy('dept:desc,id'), [kim, lee, hong]); \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex4.js" "b/\354\236\204\354\210\230\354\247\204/ex4.js" index 9ede02f..8bc2d29 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex4.js" +++ "b/\354\236\204\354\210\230\354\247\204/ex4.js" @@ -1,3 +1,69 @@ -function deepCopy(obj) {} +function deepCopy(obj, references = new WeakMap()) { -module.exports = { deepCopy }; + // 기본형이거나 함수일 경우, 그대로 반환 + if (typeof obj !== 'object' || obj === null) { + return obj; + } + + // 이미 참조한 객체가 있을 경우, 복사된 객체를 반환 + if (references.has(obj)) { + return references.get(obj); + } + + // 배열일 경우 + if (Array.isArray(obj)) { + const copy = []; + references.set(obj, copy); // 원본 객체 저장 + + for (let i = 0; i < obj.length; i++) { + copy[i] = deepCopy(obj[i], references); + } + return copy; + } + + // Set일 경우 + if (obj instanceof Set) { + const copy = new Set(); + references.set(obj, copy); // 원본 객체랑 복사본을 WeakSet에 저장 + for (let item of obj) { + copy.add(deepCopy(item, references)); // 각 값을 재귀적으로 복사 + } + return copy; + } + + // Map일 경우 + if (obj instanceof Map) { + const copyMap = new Map(); + references.set(obj, copyMap); // 원본 객체랑 복사본을 WeakMap에 저장 + for (let [key, value] of obj) { + copyMap.set(deepCopy(key, references), deepCopy(value, references)); // 키-값을 재귀적으로 복사 + } + return copyMap; + } + + // WeakSet과 WeakMap일 경우, 그대로 반환 (참조형) + if (obj instanceof WeakSet || obj instanceof WeakMap) { + return obj; + } + + // 일반 객체일 경우 + const result = {}; + references.set(obj, result); // 원본 객체를 WeakMap에 저장 + + // 1) 객체의 심볼 속성 복사 + const symbols = Object.getOwnPropertySymbols(obj); + for (let i = 0; i < symbols.length; i++) { + const symbol = symbols[i]; + result[symbol] = deepCopy(obj[symbol], references); + } + + // 2) 객체의 일반 속성 복사 + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + result[key] = deepCopy(obj[key], references); + } + } + return result; +} + +module.exports = { deepCopy }; \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex5.js" "b/\354\236\204\354\210\230\354\247\204/ex5.js" index 464a05a..0158319 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex5.js" +++ "b/\354\236\204\354\210\230\354\247\204/ex5.js" @@ -1,3 +1,54 @@ module.exports = { - searchByKoreanInitialSound: (data, firstSounds) => {}, -}; + searchByKoreanInitialSound(data, firstSounds) { + // 한글 유니코드 시작값과 끝값 + const HANGUL_START_CHARCODE = '가'.charCodeAt(0); + const HANGUL_END_CHARCODE = '힣'.charCodeAt(0); + + // 초성 + 중성 + 종성 조합의 합 + const TOTAL_SYLLABLE_COMBINATIONS = 588; + + const initialConsonants = [ + 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', + 'ㄹ', 'ㅁ', 'ㅂ','ㅃ', 'ㅅ', + 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', + 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' + ] + + // 초성 가져오기 + const getInitialSound = (char) => { + const code = char.charCodeAt(0); + if (code >= HANGUL_START_CHARCODE && code <= HANGUL_END_CHARCODE) { + // 한글 음절의 초성 반환 + const index = Math.floor((code - HANGUL_START_CHARCODE) / TOTAL_SYLLABLE_COMBINATIONS); + return initialConsonants[index] || ''; + } else { + // 한글이 아닐 경우, 그대로 반환 + return char; + } + }; + + // 초성 정규식 패턴 생성 함수 + const getInitialSoundRegex = (firstSounds) => { + const pattern = firstSounds.split('').map(char => { + if (initialConsonants.includes(char)) { + // 초성 문자는 [char]로 패턴 생성 + return `[${char}]`; + } else { + // 숫자나 기타 문자는 그대로 사용 + return char; + } + }).join(''); + return new RegExp(pattern, 'u'); // 'u' 플래그를 사용하여 유니코드 문자 인식 + }; + + // 초성 정규식 패턴을 생성 + const regex = getInitialSoundRegex(firstSounds); + + // 데이터 필터링 + return data.filter(element => { + // 문자열에서 초성 추출 + const extractedInitialSounds = Array.from(element).map(getInitialSound).join(''); + return regex.test(extractedInitialSounds); + }); + } +}; \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex6.test.ts" "b/\354\236\204\354\210\230\354\247\204/ex6.test.ts" index 680c5e6..9a96794 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex6.test.ts" +++ "b/\354\236\204\354\210\230\354\247\204/ex6.test.ts" @@ -21,4 +21,4 @@ import { promiseAllSettled, randTime } from './ex6'; randTime(33), ]) ); -})(); +})(); \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex6.ts" "b/\354\236\204\354\210\230\354\247\204/ex6.ts" index 424ca54..4ef8dd8 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex6.ts" +++ "b/\354\236\204\354\210\230\354\247\204/ex6.ts" @@ -1,4 +1,17 @@ export const randTime = (val: T): Promise => - new Promise(resolve => setTimeout(resolve, Math.random() * 1000, val)); + new Promise(resolve => setTimeout(resolve, Math.random() * 1000, val)); -export function promiseAllSettled(promises: Promise[]) {} +export function promiseAllSettled(promises: Promise[]): Promise> { + // 모든 프로미스의 결과를 담을 배열 + const results: Array<{ status: 'fulfilled' | 'rejected'; value?: T; reason?: any }> = []; + + // 모든 프로미스의 상태를 추적 + const wrappedPromises = promises.map(promise => + promise + .then(value => ({ status: 'fulfilled', value } as { status: 'fulfilled'; value: T })) + .catch(reason => ({ status: 'rejected', reason } as { status: 'rejected'; reason: any })) + ); + + // 모든 프로미스가 처리될 때까지 기다리고 결과를 반환 + return Promise.all(wrappedPromises); +} \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex7.test.ts" "b/\354\236\204\354\210\230\354\247\204/ex7.test.ts" index 62b881d..c445b6a 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex7.test.ts" +++ "b/\354\236\204\354\210\230\354\247\204/ex7.test.ts" @@ -64,7 +64,56 @@ async function test(userId: string | number) { ], }); - // 추가 테스트 코드를 작성하시오. + // 추가 테스트 코드 + assert.strictEqual(posts?.at(0)?.title, 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit'); + assert.strictEqual(posts?.at(2)?.comments[2].email,'Kariane@jadyn.tv'); + assert.deepStrictEqual(posts[3].comments, [ + { + postId: 4, + id: 16, + email: 'Christine@ayana.info', + body: 'iste ut laborum aliquid velit facere itaque\n' + + 'quo ut soluta dicta voluptate\n' + + 'error tempore aut et\n' + + 'sequi reiciendis dignissimos expedita consequuntur libero sed fugiat facilis' + }, + { + postId: 4, + id: 17, + email: 'Preston_Hudson@blaise.tv', + body: 'consequatur necessitatibus totam sed sit dolorum\n' + + 'recusandae quae odio excepturi voluptatum harum voluptas\n' + + 'quisquam sit ad eveniet delectus\n' + + 'doloribus odio qui non labore' + }, + { + postId: 4, + id: 18, + email: 'Vincenza_Klocko@albertha.name', + body: 'veritatis voluptates necessitatibus maiores corrupti\n' + + 'neque et exercitationem amet sit et\n' + + 'ullam velit sit magnam laborum\n' + + 'magni ut molestias' + }, + { + postId: 4, + id: 19, + email: 'Madelynn.Gorczany@darion.biz', + body: 'doloribus est illo sed minima aperiam\n' + + 'ut dignissimos accusantium tempore atque et aut molestiae\n' + + 'magni ut accusamus voluptatem quos ut voluptates\n' + + 'quisquam porro sed architecto ut' + }, + { + postId: 4, + id: 20, + email: 'Mariana_Orn@preston.org', + body: 'qui harum consequatur fugiat\n' + + 'et eligendi perferendis at molestiae commodi ducimus\n' + + 'doloremque asperiores numquam qui\n' + + 'ut sit dignissimos reprehenderit tempore' + } + ]); } -test(1); +test(1); \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex7.ts" "b/\354\236\204\354\210\230\354\247\204/ex7.ts" index 62812ac..c579ebb 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex7.ts" +++ "b/\354\236\204\354\210\230\354\247\204/ex7.ts" @@ -1,3 +1,63 @@ const POST_URL = 'https://jsonplaceholder.typicode.com/posts'; -export async function getPosts(userId: number | string) {} +interface Post { + userId: number; + id: number; + title: String; + body: String; +} + +interface Comment { + postId: number; + id: number; + email: String; + body: String; +} + +interface CommentResponse extends Comment { + name: String; +} + +interface PostComment { + postId: number; + title: String; + comments: Comment[]; +} + +export async function getPosts(userId: number | string): Promise { + try { + // userId로 게시글 조회 + const postResponse = await fetch(`${POST_URL}?userId=${userId}`); + const posts: Post[] = (await postResponse.json()) as Post[]; + + // 결과 반환할 객체 배열 + const postComments: PostComment[] = await Promise.all( + posts.map(async (post: Post) => { + const commentResponse = await fetch(`${POST_URL}/${post.id}/comments`); + const comments: CommentResponse[] = + (await commentResponse.json()) as CommentResponse[]; + + // 결과 반환할 객체 + let postComment: PostComment = { + postId: post.id, + title: post.title, + comments: [], + }; + + comments.forEach((comment: Comment) => { + postComment.comments.push({ + postId: comment.postId, + id: comment.id, + email: comment.email, + body: comment.body, + }); + }); + return postComment; + }) + ); + return postComments; + } catch (error) { + console.error('에러 나요ㅠ.ㅠ:', error); + return []; + } +} \ No newline at end of file diff --git "a/\354\236\204\354\210\230\354\247\204/ex8.ts" "b/\354\236\204\354\210\230\354\247\204/ex8.ts" index a67a2d2..08397e8 100644 --- "a/\354\236\204\354\210\230\354\247\204/ex8.ts" +++ "b/\354\236\204\354\210\230\354\247\204/ex8.ts" @@ -1,8 +1,25 @@ -// dummy(mock)입니다. 올바르게 수정하세요. -const debounce = (cb: any, delay: number) => (i: number) => {}; -const throttle = (cb: any, delay: number) => (i: number) => {}; +// debounce 함수 +const debounce = (cb: (i: number) => void, delay: number) => { + let timeoutId: NodeJS.Timeout | null = null; + return (i: number) => { + if (timeoutId) clearTimeout(timeoutId); + timeoutId = setTimeout(() => cb(i), delay); + }; +}; -// function throttle... +// throttle 함수 +const throttle = (cb: (i: number) => void, delay: number) => { + let isThrottled = false; + return (i: number) => { + if (!isThrottled) { + cb(i); + isThrottled = true; + setTimeout(() => { + isThrottled = false; + }, delay); + } + }; +}; const debo = debounce((a: number) => console.log(a + 1), 500); for (let i = 10; i < 15; i++) debo(i); // 15 출력