commit 9a2e09864bc19ed813c15f88a7a2cfc672093df7 Author: alena Date: Fri Feb 6 11:16:07 2026 +0300 first commit diff --git a/src/icons/Check.svg b/src/icons/Check.svg new file mode 100644 index 0000000..713d685 --- /dev/null +++ b/src/icons/Check.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/icons/Search.svg b/src/icons/Search.svg new file mode 100644 index 0000000..1b28b9c --- /dev/null +++ b/src/icons/Search.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..b02120b --- /dev/null +++ b/src/index.html @@ -0,0 +1,70 @@ + + + + + + + To Do List + + + + +
+

To Do List

+
+
+ + +
+ +
+
+
+ + +
+
+
+
+ Total Tasks: 0 +
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..e69de29 diff --git a/src/styles/components/button.css b/src/styles/components/button.css new file mode 100644 index 0000000..9adcb8f --- /dev/null +++ b/src/styles/components/button.css @@ -0,0 +1,19 @@ +.button { + display: flex; + align-items: center; + height: var(--input-height); + padding: 12px; + color: var(--color-gray-1); + background-color: var(--color-dark-2); + border: 1px solid var(--color-dark-2); + border-radius: var(--border-radius); + + &:hover { + color: var(--color-dark-2); + background-color: transparent; + } + + &:active { + scale: 1.05; + } +} \ No newline at end of file diff --git a/src/styles/components/field.css b/src/styles/components/field.css new file mode 100644 index 0000000..8a93b68 --- /dev/null +++ b/src/styles/components/field.css @@ -0,0 +1,48 @@ +.field { + position: relative; + + &:has(.field_input:not(:placeholder-shown)) .field_label { + scale: 0.7; + translate: -1.75em -2.6em; + color: var(--color-black); + } +} +.field_label { + position: absolute; + top: 50%; + left: 17px; + color: var(--color-gray-3); + translate: 0 -50%; +} +.field_input { + --fieldInputPaddingX: 16px; + --fieldSearchInputIconSize: 16px; + + width: 100%; + height: var(--input-height); + padding-inline: var(--fieldInputPaddingX); + background-color: transparent; + border: var(--border); + border-radius: var(--border-radius); + + &:hover, &:focus { + color: var(--color-dark-2); + } + + &:focus { + background-color: var(--colorgray-1); + outline: none; + } + + &[type="search"] { + &:placeholder-shown{ + padding-right: calc( + var(--fieldInputPaddingX)*2+var(--fieldSearchInputIconSize) + ); + background-color: url('/src/icons/Search.svg'); + background-position: calc(100% - var(--fieldInputPaddingX)) 50%; + background-size: var(--fieldSearchInputIconSize); + background-repeat: no-repeat; + } + } +} \ No newline at end of file diff --git a/src/styles/components/todo-item.css b/src/styles/components/todo-item.css new file mode 100644 index 0000000..479f5ae --- /dev/null +++ b/src/styles/components/todo-item.css @@ -0,0 +1,99 @@ +.todo_item { + display: flex; + align-items: center; + column-gap: 12px; + padding-left: 10px; + border: var(--border); + border-radius: var(--border-radius); + transition-duration: var(--transition-duration); + + &:hover { + background-color: var(--color-gray-1); + + } + + &.is-disappearing { + opacity: 0; + translate: 0 -75%; + transition-duration: calc(var(--transition-duration)*2); + pointer-events: none; + + & ~ .todo_item { + translate: 0 calc((100% + var(--todoListRowGap)) * -1); + transition-delay: var(--transition-duration); + transition-duration: var(--transition-duration); + pointer-events: none; + } + } +} +.todo_item_checkbox { + flex-shrink: 0; + appearance: none; + position: relative; + width: 20px; + height: 20px; + margin: 0; + border: 1px solid var(--color-gray-4); + border-radius: 4px; + + &:not(:checked) { + &::after { + opacity: 0; + } + } + + &:checked { + background-color: var(--color-dark-2); + border-color: var(--color-dark-2); + + & + .todo-item_label { + color: var(--color-gray-4); + text-decoration: line-through; + } + } + + &:after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + translate: -50% -50%; + width: 16px; + height: 16px; + background: url('/src/icons/Check.svg') center/contain no-repeat; + } + +} + +.todo-item_label { + width: 100%; + pointer-events: none; +} + +.todo_item_delete-button { + flex-shrink: 0; + display: inline-flex; + align-items: center; + justify-content: center; + width: 44px; + height: 44px; + margin-left: auto; + padding: 0; + color: var(--color-gray-4); + background-color: transparent; + border: none; + border-radius: inherit; + + &:hover { + color: var(--color-white); + background-color: var(--color-dark-1); + } + + &:active { + scale: 1.05; + } + + * { + pointer-events: none; + } + } diff --git a/src/styles/components/todo.css b/src/styles/components/todo.css new file mode 100644 index 0000000..79bcd4e --- /dev/null +++ b/src/styles/components/todo.css @@ -0,0 +1,61 @@ +.todo { + display: flex; + flex-direction: column; + row-gap: 24px; + width: 100%; + max-width: 404px; + min-height: 429px; + padding: 24px; + background-color: var(--color-white); + border: var(--border); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow); +} +.todo_title { + text-align: center; + font-size: 24px; + line-height: 1.2; + font-weight: 600; + letter-spacing: -2%; +} +.todo_form { + display: flex; + column-gap: 16px; +} +.todo_field { + width: 100%; +} +.todo_info { + display: flex; + justify-content: space-between; + align-items: center; + column-gap: 16px; + font-weight: 600; +} +.todo_delete-all-button { + padding: 0; + background-color: transparent; + border: none; + &:hover { + color: var(--color-gray-4); + } + &:not(.is-visiable) { + opacity: 0; + visibility: hidden; + } +} +.todo_list, .todo_empty-message { + &:empty { + display: none; + } +} +.todo_list { + --todoListRowGap: 8px; + + display: grid; + row-gap: var(--todoListRowGap); +} +.todo_empty-message { + text-align: center; + color: var(--color-gray-4); +} \ No newline at end of file diff --git a/src/styles/fonts.css b/src/styles/fonts.css new file mode 100644 index 0000000..18a8544 --- /dev/null +++ b/src/styles/fonts.css @@ -0,0 +1 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap'); \ No newline at end of file diff --git a/src/styles/globals.css b/src/styles/globals.css new file mode 100644 index 0000000..8f145ad --- /dev/null +++ b/src/styles/globals.css @@ -0,0 +1,17 @@ +body { + display: flex; + justify-content: center; + align-items: start; + min-height: 100vh; + padding: 100px 30px; + font-family: "Inter", sans-serif; + background-color: var(--color-gray-1); +} +input, label, button { + transition-duration: var(--transition-duration); +} +:focus-visible { + outline: 2px dashed var(--color-black); + outline-offset: 4px; + transition-duration: 0s !important; +} \ No newline at end of file diff --git a/src/styles/index.css b/src/styles/index.css new file mode 100644 index 0000000..f1fa14b --- /dev/null +++ b/src/styles/index.css @@ -0,0 +1,9 @@ +@import "normalize.css"; +@import "fonts.css"; +@import "veriables.css"; +@import "globals.css"; + +@import "components/button.css"; +@import "components/field.css"; +@import "components/todo-item.css"; +@import "components/todo.css"; \ No newline at end of file diff --git a/src/styles/normalize.css b/src/styles/normalize.css new file mode 100644 index 0000000..9f50e29 --- /dev/null +++ b/src/styles/normalize.css @@ -0,0 +1,210 @@ +/** + Нормализация блочной модели + */ +*, +::before, +::after { + box-sizing: border-box; +} + +/** + Убираем внутренние отступы слева тегам списков, + у которых есть атрибут class + */ +:where(ul, ol):where([class]) { + padding-left: 0; +} + +/** + Убираем внешние отступы body и двум другим тегам, + у которых есть атрибут class + */ +body, +:where(blockquote, figure, fieldset):where([class]) { + margin: 0; +} + +/** + Убираем внешние отступы вертикали нужным тегам, + у которых есть атрибут class + */ +:where( + h1, + h2, + h3, + h4, + h5, + h6, + p, + ul, + ol, + dl +):where([class]) { + margin-block: 0; +} + +:where(dd[class]) { + margin-left: 0; +} + +:where(fieldset[class]) { + padding: 0; + border: none; +} + +/** + Убираем стандартный маркер маркированному списку, + у которого есть атрибут class + */ +:where(ul[class]) { + list-style: none; +} + +:where(address[class]) { + font-style: normal; +} + +/** + Обнуляем вертикальные внешние отступы параграфа, + объявляем локальную переменную для внешнего отступа вниз, + чтобы избежать взаимодействие с более сложным селектором + */ +p { + --paragraphMarginBottom: 24px; + + margin-block: 0; +} + +/** + Внешний отступ вниз для параграфа без атрибута class, + который расположен не последним среди своих соседних элементов + */ +p:where(:not([class]):not(:last-child)) { + margin-bottom: var(--paragraphMarginBottom); +} + + +/** + Упрощаем работу с изображениями и видео + */ +img, +video { + display: block; + max-width: 100%; + height: auto; +} + +/** + Наследуем свойства шрифт для полей ввода + */ +input, +textarea, +select, +button { + font: inherit; +} + +html { + /** + Пригодится в большинстве ситуаций + (когда, например, нужно будет "прижать" футер к низу сайта) + */ + height: 100%; + /** + Убираем скачок интерфейса по горизонтали + при появлении / исчезновении скроллбара + */ + scrollbar-gutter: stable; + /** + Плавный скролл + */ + scroll-behavior: smooth; +} + +body { + /** + Пригодится в большинстве ситуаций + (когда, например, нужно будет "прижать" футер к низу сайта) + */ + min-height: 100%; + /** + Унифицированный интерлиньяж + */ + line-height: 1.5; +} + +/** + Нормализация высоты элемента ссылки при его инспектировании в DevTools + */ +a:where([class]) { + display: inline-flex; +} + +/** + Курсор-рука при наведении на элемент + */ +button, +label { + cursor: pointer; +} + +/** + Убирает серую подсветку при тапе на мобильных устройствах (iOS/Android) + */ +button { + -webkit-tap-highlight-color: transparent; +} + +/** + Приводим к единому цвету svg-элементы + (за исключением тех, у которых уже указан + атрибут fill со значением 'none' или начинается с 'url') + */ +:where([fill]:not( + [fill="none"], + [fill^="url"] +)) { + fill: currentColor; +} + +/** + Приводим к единому цвету svg-элементы + (за исключением тех, у которых уже указан + атрибут stroke со значением 'none') + */ +:where([stroke]:not( + [stroke="none"], + [stroke^="url"] +)) { + stroke: currentColor; +} + +/** + Чиним баг задержки смены цвета при взаимодействии с svg-элементами + */ +svg * { + transition-property: fill, stroke; +} + +/** + Приведение рамок таблиц в классический 'collapse' вид + */ +:where(table) { + border-collapse: collapse; + border-color: currentColor; +} + +/** + Удаляем все анимации и переходы для людей, + которые предпочитают их не использовать + */ +@media (prefers-reduced-motion: reduce) { + *, + ::before, + ::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} \ No newline at end of file diff --git a/src/styles/veriables.css b/src/styles/veriables.css new file mode 100644 index 0000000..d366be4 --- /dev/null +++ b/src/styles/veriables.css @@ -0,0 +1,21 @@ +:root { + --color-white: #ffffff; + --color-black: #000000; + + --color-dark-1: #1E1E1E; + --color-dark-2: #2C2C2C; + + --color-gray-1: #F5F5F5; + --color-gray-2: #D9D9D9; + --color-gray-3: #B3B3B3; + --color-gray-4: #757575; + + --border: 1px solid var(--color-gray-2); + --border-radius: 8px; + + --box-shadow: 0px 4px 4px -4px rgba(12, 12, 13, 0.05), 0px 16px 32px -4px rgba(12, 12, 13, 0.1); + + --input-height: 40px; + + --transition-duration: 0.2s +} \ No newline at end of file