├── src ├── scss │ ├── layout │ │ ├── _grid.scss │ │ ├── _sidebar.scss │ │ ├── _index.scss │ │ └── _main.scss │ ├── components │ │ ├── _card.scss │ │ ├── _index.scss │ │ ├── _alert.scss │ │ ├── _badges.scss │ │ └── _button.scss │ ├── utils │ │ ├── _functions.scss │ │ ├── _placeholders.scss │ │ ├── _variables.scss │ │ ├── _index.scss │ │ └── _mixins.scss │ ├── base │ │ ├── _index.scss │ │ ├── _fonts.scss │ │ ├── _base.scss │ │ └── _reset.scss │ ├── --examples-- │ │ ├── lesson-05 │ │ │ ├── _btn-scema.scss │ │ │ ├── _base.scss │ │ │ ├── _scopes.scss │ │ │ ├── _button.scss │ │ │ └── _variables.scss │ │ ├── lesson-06 │ │ │ ├── _nesting.scss │ │ │ ├── _ampersand.scss │ │ │ └── _combinators.scss │ │ ├── lesson-14 │ │ │ ├── _map.scss │ │ │ ├── _alerts.scss │ │ │ └── _colors.scss │ │ ├── lesson-07 │ │ │ ├── example.css │ │ │ ├── _badge.scss │ │ │ ├── _math.scss │ │ │ └── _task.scss │ │ ├── lesson-12 │ │ │ ├── _examples.scss │ │ │ ├── _functions.scss │ │ │ ├── _mixins.scss │ │ │ └── _decimal.scss │ │ ├── lesson-11 │ │ │ ├── _each.scss │ │ │ ├── _for.scss │ │ │ └── _if.scss │ │ ├── lesson-13 │ │ │ └── _list.scss │ │ ├── lesson-09 │ │ │ └── _extend.scss │ │ └── lesson-10 │ │ │ └── _mixins.scss │ └── main.scss ├── js │ └── main.js ├── img │ ├── logo-sass.png │ ├── webp │ │ ├── logo-sass.webp │ │ └── employee-1.webp │ ├── badges │ │ └── employee-1.png │ ├── icons │ │ ├── github.svg │ │ ├── gem.svg │ │ ├── info.svg │ │ ├── close.svg │ │ ├── check.svg │ │ ├── warning.svg │ │ └── danger.svg │ └── icons.svg └── fonts │ ├── Montserrat-Bold.woff2 │ └── Montserrat-Regular.woff2 ├── demo ├── main-page.jpg ├── deploy-status.png ├── how-it-works.png ├── repo-settings.png ├── template-step-1.png ├── template-step-2.png ├── gh-actions-perm-1.png ├── gh-actions-perm-2.png └── project-structure.md ├── postcss.config.cjs ├── .gitignore ├── index.html ├── package.json ├── LICENSE ├── vite.config.js ├── README.md └── public └── sass.svg /src/scss/layout/_grid.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/components/_card.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/layout/_sidebar.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/utils/_functions.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/utils/_placeholders.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scss/utils/_variables.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/js/main.js: -------------------------------------------------------------------------------- 1 | import "../scss/main.scss"; 2 | -------------------------------------------------------------------------------- /src/scss/base/_index.scss: -------------------------------------------------------------------------------- 1 | @forward "fonts"; 2 | @forward "base"; 3 | @forward "reset"; 4 | -------------------------------------------------------------------------------- /src/scss/layout/_index.scss: -------------------------------------------------------------------------------- 1 | @forward "main"; 2 | @forward "grid"; 3 | @forward "sidebar"; 4 | -------------------------------------------------------------------------------- /demo/main-page.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/demo/main-page.jpg -------------------------------------------------------------------------------- /demo/deploy-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/demo/deploy-status.png -------------------------------------------------------------------------------- /demo/how-it-works.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/demo/how-it-works.png -------------------------------------------------------------------------------- /demo/repo-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/demo/repo-settings.png -------------------------------------------------------------------------------- /src/img/logo-sass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/src/img/logo-sass.png -------------------------------------------------------------------------------- /demo/template-step-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/demo/template-step-1.png -------------------------------------------------------------------------------- /demo/template-step-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/demo/template-step-2.png -------------------------------------------------------------------------------- /demo/gh-actions-perm-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/demo/gh-actions-perm-1.png -------------------------------------------------------------------------------- /demo/gh-actions-perm-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/demo/gh-actions-perm-2.png -------------------------------------------------------------------------------- /src/img/webp/logo-sass.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/src/img/webp/logo-sass.webp -------------------------------------------------------------------------------- /src/img/badges/employee-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/src/img/badges/employee-1.png -------------------------------------------------------------------------------- /src/img/webp/employee-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/src/img/webp/employee-1.webp -------------------------------------------------------------------------------- /src/fonts/Montserrat-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/src/fonts/Montserrat-Bold.woff2 -------------------------------------------------------------------------------- /src/fonts/Montserrat-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goitacademy/sass-course-code/HEAD/src/fonts/Montserrat-Regular.woff2 -------------------------------------------------------------------------------- /src/scss/components/_index.scss: -------------------------------------------------------------------------------- 1 | @forward "button"; 2 | // @forward "alert"; 3 | // @forward "badges"; 4 | // @forward "card"; 5 | -------------------------------------------------------------------------------- /src/scss/utils/_index.scss: -------------------------------------------------------------------------------- 1 | @forward "variables"; 2 | // @forward "mixins"; 3 | // @forward "functions"; 4 | // @forward "placeholders"; 5 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-05/_btn-scema.scss: -------------------------------------------------------------------------------- 1 | $font-size: 16px !default; 2 | $btn-color: white !default; 3 | $btn-bgcolor: hotpink !default; 4 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-05/_base.scss: -------------------------------------------------------------------------------- 1 | body { 2 | min-width: 100vw; 3 | min-height: 100vh; 4 | 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-06/_nesting.scss: -------------------------------------------------------------------------------- 1 | .section { 2 | width: 100%; 3 | 4 | .title { 5 | color: teal; 6 | } 7 | 8 | .text { 9 | font-size: 14px; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require("postcss-sort-media-queries")({ 4 | sort: "mobile-first", // default value 5 | }), 6 | // require("autoprefixer"), 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-14/_map.scss: -------------------------------------------------------------------------------- 1 | @use "./colors" as c; 2 | 3 | /* 4 | Перевикористовуємо мапу кольорів 5 | для стилізації кнопки 6 | */ 7 | .button { 8 | color: c.get-color("primary"); 9 | background-color: c.get-color("background"); 10 | } 11 | -------------------------------------------------------------------------------- /src/scss/utils/_mixins.scss: -------------------------------------------------------------------------------- 1 | @use "sass:map"; 2 | 3 | @mixin viewport-md { 4 | @media (min-width: 767px) { 5 | @content; 6 | } 7 | } 8 | 9 | @mixin text-gradient { 10 | background: var(--hero-name-background); 11 | background-clip: text; 12 | color: transparent; 13 | } 14 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-05/_scopes.scss: -------------------------------------------------------------------------------- 1 | $color-primary: teal; // global scope 2 | 3 | body { 4 | $color-primary: lightblue; // local scope 5 | $color-secondary: white !global; 6 | background-color: $color-primary; 7 | } 8 | 9 | p { 10 | color: $color-secondary; // undefined 11 | background-color: $color-primary; 12 | } 13 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-14/_alerts.scss: -------------------------------------------------------------------------------- 1 | $types: ( 2 | "primary": #f07f2e, 3 | "success": #82c43c, 4 | "danger": #fc5a5a, 5 | "warning": #a461d8, 6 | "info": #4e75ff, 7 | ); 8 | 9 | /* Генеруємо набір класів повідомлень */ 10 | @each $key, $value in $types { 11 | .alert-#{$key} { 12 | background-color: $value; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-05/_button.scss: -------------------------------------------------------------------------------- 1 | @use "sass:math"; 2 | @use "btn-scema" as vars with ( 3 | $font-size: 10px, 4 | $btn-color: black, 5 | $btn-bgcolor: lightblue 6 | ); 7 | 8 | .small-btn { 9 | font-size: vars.$font-size; 10 | color: vars.$btn-color; 11 | background-color: vars.$btn-bgcolor; 12 | } 13 | 14 | @debug math.$pi; 15 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-07/example.css: -------------------------------------------------------------------------------- 1 | /*|============================ 2 | | Створити класи для бейджів 3 | |============================ 4 | */ 5 | 6 | .badge-completed { 7 | background-color: #a461d8; 8 | } 9 | 10 | .badge-ended { 11 | background-color: #fc5a5a; 12 | } 13 | 14 | .badge-active { 15 | background-color: #82c43c; 16 | } 17 | -------------------------------------------------------------------------------- /src/scss/base/_fonts.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Montserrat"; 3 | src: url("../fonts/Montserrat-Regular.woff2") format('woff2'); 4 | font-weight: 400; 5 | font-display: swap; 6 | } 7 | 8 | @font-face { 9 | font-family: "Montserrat"; 10 | src: url("../fonts/Montserrat-Bold.woff2") format('woff2'); 11 | font-weight: 700; 12 | font-display: swap; 13 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-12/_examples.scss: -------------------------------------------------------------------------------- 1 | @use "mixins" as m; 2 | @use "functions" as f; 3 | 4 | .title { 5 | // font-size: 20px; 6 | // font-style: normal; 7 | // font-weight: 600; 8 | // line-height: 28px; /* 140% */ 9 | // letter-spacing: 0.5px; 10 | // text-align: center; 11 | 12 | @include m.fonts(20px, 600, 28px, 0.5px, center); 13 | } 14 | 15 | .container { 16 | // width: 1000px; 17 | width: f.rem(1000px); 18 | } 19 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-11/_each.scss: -------------------------------------------------------------------------------- 1 | // @each at-rule with list 2 | $sizes: 8, 16, 20; 3 | 4 | @each $size in $sizes { 5 | .p-#{$size} { 6 | padding: #{$size}px; 7 | } 8 | } 9 | 10 | // @each at-rule with map 11 | $spacers: ( 12 | "sm": 24, 13 | "md": 32, 14 | "lg": 36, 15 | "xl": 68, 16 | ); 17 | 18 | @each $key, $value in $spacers { 19 | .margin-#{$key} { 20 | margin: #{$value}px; 21 | } 22 | } 23 | 24 | // next code 25 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-05/_variables.scss: -------------------------------------------------------------------------------- 1 | // $color-primary-text: #888; // kebeb case 2 | // $color-blue-text: lightblue; // kebeb case 3 | 4 | // $colorPrimaryText: #888; // camel case 5 | // $colorBlueText: lightblue; // camel case 6 | 7 | // $color_primary_text: #888; // snake case 8 | // $color_blue_text: lightblue; // snake case 9 | 10 | $font-size: 16px; 11 | 12 | .title { 13 | font-size: $font-size; 14 | } 15 | 16 | $font-size: 10px; 17 | 18 | .subtitle { 19 | font-size: $font-size; 20 | } 21 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-12/_functions.scss: -------------------------------------------------------------------------------- 1 | // Function statement 2 | @use "sass:math"; 3 | 4 | @function strip-unit($value) { 5 | @if type-of($value) != "number" { 6 | @error "#{$value} is not a number."; 7 | } 8 | 9 | @if type-of($value) == "number" and not unitless($value) { 10 | @return math.div($value, ($value * 0 + 1)); 11 | } 12 | 13 | @return $value; 14 | } 15 | 16 | @function rem($px-value, $base-font-size: 16px) { 17 | @return #{math.div(strip-unit($px-value), strip-unit($base-font-size))}rem; 18 | } 19 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-11/_for.scss: -------------------------------------------------------------------------------- 1 | // @for at-rule with calculations 2 | $base-weight: 400; 3 | 4 | @for $i from 0 through 3 { 5 | // 1 step: $i = 0 6 | // 2 step: $i = 1 7 | // 3 step: $i = 2 8 | // 4 step: $i = 3 9 | 10 | .fw-#{$base-weight+($i * 100)} { 11 | font-weight: $base-weight + ($i * 100); 12 | } 13 | } 14 | 15 | // difference between "through" and "to" 16 | // @for $i from 0 to 3 { 17 | // @debug "with to #{$i}"; 18 | // } 19 | 20 | @for $_ from 0 through 3 { 21 | @debug $_; 22 | } 23 | 24 | $n: 0; 25 | 26 | @while $n < 4 { 27 | $n: $n + 1; 28 | } 29 | -------------------------------------------------------------------------------- /src/scss/components/_alert.scss: -------------------------------------------------------------------------------- 1 | // Extending selectors 2 | // .notification { 3 | // border-radius: 10px; 4 | 5 | // > .icon { 6 | // display: block; 7 | // } 8 | // } 9 | div:not(:last-child) { 10 | margin: 0 auto; 11 | margin-bottom: 24px; 12 | } 13 | 14 | .notification-icon, 15 | .notification-btn-icon { 16 | fill: currentColor; 17 | } 18 | 19 | .notification-text { 20 | margin: 0; 21 | flex-grow: 1; 22 | } 23 | .notification-btn { 24 | font-family: inherit; 25 | color: currentColor; 26 | background-color: transparent; 27 | border: none; 28 | cursor: pointer; 29 | } 30 | -------------------------------------------------------------------------------- /src/scss/components/_badges.scss: -------------------------------------------------------------------------------- 1 | @use "../base/fonts"; 2 | 3 | .badges { 4 | display: flex; 5 | flex-flow: wrap; 6 | justify-content: center; 7 | align-items: center; 8 | gap: 2rem; 9 | 10 | &-item { 11 | } 12 | 13 | &-link { 14 | display: block; 15 | border-radius: 5rem; 16 | color: var(--main-text-color); 17 | text-decoration: none; 18 | background: var(--brand-color); 19 | padding: 0.8rem 1.8rem; 20 | transition: 0.2s ease; 21 | 22 | &:hover { 23 | background: var(--brand-light-color); 24 | } 25 | } 26 | } 27 | .no-link { 28 | pointer-events: none; 29 | } 30 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Lesson 12 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-06/_ampersand.scss: -------------------------------------------------------------------------------- 1 | // .link { 2 | // color: black; 3 | 4 | // &:hover, 5 | // &:focus { 6 | // color: red; 7 | // } 8 | // } 9 | 10 | .button { 11 | background: teal { 12 | position: center; 13 | repeat: no-repeat; 14 | } 15 | 16 | // color: red; 17 | 18 | &:hover, 19 | &:focus { 20 | color: blue; 21 | } 22 | } 23 | 24 | .button-icon { 25 | width: 20px; 26 | height: 20px; 27 | 28 | &:hover { 29 | width: 50px; 30 | height: 50px; 31 | } 32 | 33 | .button:hover & { 34 | font-size: 20px; 35 | } 36 | } 37 | 38 | .button-label { 39 | font-size: 16px; 40 | 41 | .button:hover & { 42 | font-size: 20px; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "starter-kit", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build --base=/starter-kit/", 9 | "preview": "vite preview", 10 | "watch": "npx vite build --watch" 11 | }, 12 | "browserslist": [ 13 | "cover 99.5%" 14 | ], 15 | "devDependencies": { 16 | "autoprefixer": "^10.4.4", 17 | "fast-glob": "^3.3.1", 18 | "imagemin": "^8.0.1", 19 | "imagemin-webp": "^8.0.0", 20 | "postcss-sort-media-queries": "^5.2.0", 21 | "sass": "^1.68.0", 22 | "sharp": "^0.32.6", 23 | "svgo": "^3.0.2", 24 | "vite": "^4.4.5", 25 | "vite-plugin-image-optimizer": "^1.1.7" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/scss/components/_button.scss: -------------------------------------------------------------------------------- 1 | %btn { 2 | font-family: Montserrat; 3 | font-size: 14px; 4 | font-weight: 500; 5 | line-height: 20px; /* 142.857% */ 6 | letter-spacing: 0.5px; 7 | color: #fafafb; 8 | 9 | background-color: #f07f2e; 10 | border: none; 11 | cursor: pointer; 12 | transition: 300ms; 13 | 14 | &:hover { 15 | background-color: #f15c27; 16 | box-shadow: 0px 4px 10px 0px rgba(240, 127, 46, 0.25); 17 | } 18 | } 19 | 20 | .btn-sm { 21 | @extend %btn; 22 | 23 | display: inline-flex; 24 | padding: 4px 8px; 25 | } 26 | .btn-md { 27 | @extend %btn; 28 | 29 | display: inline-flex; 30 | padding: 8px 12px; 31 | } 32 | .btn-lg { 33 | @extend %btn; 34 | 35 | display: inline-flex; 36 | padding: 16px 20px; 37 | } 38 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-07/_badge.scss: -------------------------------------------------------------------------------- 1 | .badge-info { 2 | color: #b5b5be; 3 | font-size: 14px; 4 | line-height: 20px; /* 142.857% */ 5 | letter-spacing: 0.5px; 6 | text-align: right; 7 | } 8 | .badge { 9 | min-width: 96px; 10 | padding: 4px 8px; 11 | 12 | color: #fff; 13 | text-align: center; 14 | font-size: 14px; 15 | font-style: normal; 16 | font-weight: 500; 17 | line-height: 20px; /* 142.857% */ 18 | letter-spacing: 0.07px; 19 | 20 | border-radius: 20px; 21 | background-color: #92929d; 22 | } 23 | 24 | // Practice 25 | $status: ( 26 | "completed": #a461d8, 27 | "ended": #fc5a5a, 28 | "active": #82c43c, 29 | ); 30 | 31 | @each $status-text, $color in $status { 32 | .badge-#{$status-text} { 33 | background-color: $color; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-07/_math.scss: -------------------------------------------------------------------------------- 1 | /*|============================ 2 | | Додавання & Віднімання 3 | |============================ 4 | */ 5 | .box { 6 | width: 600px + 30px; 7 | width: 600px - 30px; 8 | } 9 | /*|============================ 10 | | Множення & Ділення 11 | |============================ 12 | */ 13 | $vaule: 600px; 14 | .box { 15 | width: 600px * 5; 16 | width: 600px * 2 + 50px; 17 | width: 2 * (600px + 50px); 18 | 19 | width: $vaule / 5; 20 | width: (600px / 2); 21 | width: 600px / 3 + 100px; 22 | } 23 | /*|============================ 24 | | Інтерполяція 25 | |============================ 26 | */ 27 | $margin: 100px; 28 | .box { 29 | width: $margin * 2; 30 | } 31 | .box { 32 | width: calc($margin * 2); 33 | width: calc(#{$margin} * 2); 34 | } 35 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-12/_mixins.scss: -------------------------------------------------------------------------------- 1 | @use "decimal" as *; 2 | @use "functions" as *; 3 | 4 | @mixin fonts($fs, $fw: null, $lh: null, $ls: null, $align: null) { 5 | @if $fs { 6 | font-size: $fs; 7 | } 8 | 9 | @if $fw { 10 | font-weight: $fw; 11 | } 12 | 13 | @if $lh { 14 | @if $lh == normal { 15 | line-height: normal; 16 | } @else { 17 | $lh: calc(strip-unit($lh) / strip-unit($fs)); 18 | line-height: decimal-round($lh, 2); 19 | } 20 | } 21 | 22 | @if $ls { 23 | @if $ls == normal { 24 | letter-spacing: normal; 25 | } @else { 26 | $ls: calc(strip-unit($ls) / strip-unit($fs)); 27 | letter-spacing: #{decimal-round($ls, 2)}em; 28 | } 29 | } 30 | 31 | @if $align { 32 | text-align: $align; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/img/icons/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-14/_colors.scss: -------------------------------------------------------------------------------- 1 | @use "sass:map"; 2 | 3 | // |============================ 4 | // | Набір змінних не повʼязаних 5 | // | між собою 6 | // |============================ 7 | $color-primary: #8e3329; 8 | $color-accent: #d98328; 9 | $color-secondary: #5a1321; 10 | $color-foreground: #191919; 11 | $color-background: #e9e9e9; 12 | 13 | // |============================ 14 | // | Обєʼднані значення (мапа) 15 | // |============================ 16 | $colors: ( 17 | "primary": #8e3329, 18 | "accent": #d98328, 19 | "secondary": #5a1321, 20 | "foreground": #191919, 21 | "background": #e9e9e9, 22 | ); 23 | 24 | /* Отримуємо значення з мапи */ 25 | body { 26 | background-color: map.get($colors, "background"); 27 | } 28 | 29 | // Функція-утиліта для доступу до властивостей мапи 30 | @function get-color($key) { 31 | @return map.get($colors, $key); 32 | } 33 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-13/_list.scss: -------------------------------------------------------------------------------- 1 | @use "sass:list"; 2 | 3 | // List examples 4 | $list: 8, 10, 12, 14, 16; 5 | 6 | $list: 1px solid red; 7 | 8 | // list.nth() function 9 | $numbers: 10px, 12px, 16px; 10 | @debug list.nth($numbers, 2); // 12px 11 | 12 | // list.length() function 13 | $colors: lightgreen, tomato, lightblue; 14 | @debug list.length($colors); // 3 15 | 16 | // use list with @each 17 | $sizes: 40px, 50px, 80px; 18 | 19 | @each $size in $sizes { 20 | .icon-#{$size} { 21 | font-size: $size; 22 | height: $size; 23 | width: $size; 24 | } 25 | } 26 | 27 | // use list with @for 28 | $button-types: ".btn-sm", ".btn-md", ".btn-lg", ".btn-xl"; 29 | 30 | @mixin btn-size($types) { 31 | @for $i from 1 through list.length($types) { 32 | #{list.nth($types, $i)} { 33 | $factor: ($i * 5 - 5); 34 | 35 | padding: (5px + $factor) (10px + $factor); 36 | border-radius: (10px + $factor); 37 | } 38 | } 39 | } 40 | 41 | @include btn-size($button-types); 42 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-06/_combinators.scss: -------------------------------------------------------------------------------- 1 | // // descendant selector 2 | // div p { 3 | // /* Вибере всі

елементи, які є нащадками для

*/ 4 | // color: black; 5 | // } 6 | 7 | // // child selector 8 | // div > p { 9 | // /* Вибере всі

елементи, які є безпосередніми дітьми

*/ 10 | // color: black; 11 | // } 12 | 13 | // // adjacent sibling selector 14 | // h2 + p { 15 | // /* Вибере елемент

, який є наступним сусідом

*/ 16 | // color: black; 17 | // } 18 | 19 | // // general sibling selector 20 | // h2 ~ p { 21 | // /* Вибере всі

елементи, які є наступними сусідами

*/ 22 | // color: black; 23 | // } 24 | 25 | /** 26 | |============================ 27 | | Using combinators in SASS 28 | |============================ 29 | */ 30 | ul > { 31 | li { 32 | list-style: none; 33 | } 34 | } 35 | 36 | h2 { 37 | + p { 38 | border-top: 1px solid gray; 39 | } 40 | } 41 | 42 | p { 43 | ~ { 44 | span { 45 | opacity: 0.8; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/scss/base/_base.scss: -------------------------------------------------------------------------------- 1 | @use "../utilities/mixins"; 2 | 3 | html { 4 | font-size: 8px; 5 | @include mixins.viewport-md { 6 | font-size: 10px; 7 | } 8 | } 9 | body { 10 | font-family: "Montserrat"; 11 | background: var(--main-color); 12 | color: var(--main-text-color); 13 | font-size: 2.4rem; 14 | transition: background 0.2s ease, color 0.2s ease; 15 | } 16 | 17 | .wrapper { 18 | min-height: 100vh; 19 | text-align: center; 20 | display: flex; 21 | flex-flow: column; 22 | } 23 | 24 | .container { 25 | max-width: 1180px; 26 | margin: 0 auto; 27 | padding: 0 2rem; 28 | } 29 | 30 | .dark { 31 | color-scheme: dark; 32 | } 33 | 34 | .title { 35 | font-size: 4rem; 36 | 37 | span { 38 | font-size: 5rem; 39 | text-transform: uppercase; 40 | font-weight: 700; 41 | @include mixins.text-gradient; 42 | } 43 | } 44 | 45 | .footer { 46 | padding: 3rem 0; 47 | font-size: 1.6rem; 48 | 49 | a { 50 | text-decoration: none; 51 | color: var(--brand-color); 52 | transition: 0.2s ease; 53 | &:hover { 54 | color: var(--brand-light-color); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 GoIT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-11/_if.scss: -------------------------------------------------------------------------------- 1 | @use "sass:math"; 2 | 3 | // @if statement 4 | @mixin avatar($size, $circle: false) { 5 | width: $size; 6 | height: $size; 7 | 8 | @if $circle { 9 | border-radius: 50%; 10 | } 11 | } 12 | 13 | .square-avatar { 14 | @include avatar(100px); 15 | } 16 | .circle-avatar { 17 | @include avatar(100px, $circle: true); 18 | } 19 | 20 | // Conditional statements 21 | @mixin fonts($fs, $fw: null, $lh: null, $ls: null, $align: null) { 22 | font-size: $fs; 23 | 24 | @if $fw { 25 | font-weight: $fw; 26 | } 27 | 28 | @if $lh { 29 | @if $lh == normal { 30 | line-height: normal; 31 | } @else if math.unit($lh) == "px" { 32 | line-height: calc($lh / $fs); 33 | } @else { 34 | @error "$lh value #{$lh} is incorrect"; 35 | } 36 | } 37 | 38 | @if $ls { 39 | @if $ls == normal { 40 | letter-spacing: normal; 41 | } @else { 42 | letter-spacing: #{calc($ls/$fs)}em; 43 | } 44 | } 45 | 46 | @if $align { 47 | text-align: $align; 48 | } 49 | } 50 | 51 | .title { 52 | // With keyword args 53 | @include fonts(20px, $fw: 600, $lh: 28px, $ls: 0.5px, $align: center); 54 | } 55 | -------------------------------------------------------------------------------- /src/img/icons/gem.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/scss/main.scss: -------------------------------------------------------------------------------- 1 | // @use "utilities"; 2 | // @use "base"; 3 | // @use "layout"; 4 | // @use "components"; 5 | 6 | // Examples lesson 06 7 | // @use "--examples--/lesson-06/nesting"; 8 | // @use "--examples--/lesson-06/combinators"; 9 | // @use "--examples--/lesson-06/ampersand"; 10 | 11 | // Examples lesson 07 12 | // @use "--examples--/lesson-07/math"; 13 | // @use "--examples--/lesson-07/task-badge"; 14 | // @use "base/fonts"; 15 | // @use "components/task"; 16 | 17 | // Examples lesson 09 18 | // @use "base/fonts"; 19 | // @use "components/alert"; 20 | // @use "--examples--/lesson-09/extend"; 21 | 22 | // Examples lesson 10 23 | // @use "base/fonts"; 24 | // @use "components/button"; 25 | // @use "--examples--/lesson-10/mixins"; 26 | 27 | // Examples lesson 11 28 | // @use "base/fonts"; 29 | // @use "components/button"; 30 | // @use "--examples--/lesson-11/if"; 31 | // @use "--examples--/lesson-11/each"; 32 | // @use "--examples--/lesson-11/for"; 33 | 34 | // Examples lesson 12 35 | // @use "--examples--/lesson-12/examples"; 36 | // @use "--examples--/lesson-12/functions"; 37 | 38 | // Examples lesson 13 39 | // @use "--examples--/lesson-13/list"; 40 | 41 | // Examples lesson 14 42 | @use "--examples--/lesson-14/map"; 43 | @use "--examples--/lesson-14/alerts"; 44 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-07/_task.scss: -------------------------------------------------------------------------------- 1 | body { 2 | min-height: 100vh; 3 | 4 | display: flex; 5 | align-items: center; 6 | justify-content: center; 7 | flex-direction: column; 8 | gap: 30px; 9 | 10 | background-color: #292932; 11 | } 12 | 13 | .task { 14 | display: flex; 15 | justify-content: space-between; 16 | 17 | width: 589px; 18 | padding: 24px; 19 | 20 | background-color: #1c1c24; 21 | border-radius: 12px; 22 | } 23 | .task-caption { 24 | margin-bottom: 8px; 25 | 26 | font-size: 16px; 27 | font-weight: 500; 28 | line-height: 24px; 29 | letter-spacing: 0.5px; 30 | color: #fafafb; 31 | } 32 | .task-deadline { 33 | margin-bottom: 18px; 34 | 35 | color: #fafafb; 36 | font-size: 14px; 37 | line-height: 20px; /* 142.857% */ 38 | letter-spacing: 0.5px; 39 | } 40 | .task-deadline-date { 41 | color: #b5b5be; 42 | } 43 | 44 | .performer { 45 | display: flex; 46 | align-items: center; 47 | gap: 8px; 48 | } 49 | .performer-avatar { 50 | display: block; 51 | max-width: 100%; 52 | height: auto; 53 | } 54 | .performer-bio { 55 | color: #b5b5be; 56 | font-size: 14px; 57 | line-height: 20px; 58 | letter-spacing: 0.5px; 59 | } 60 | 61 | .task-badges { 62 | display: flex; 63 | flex-direction: column; 64 | justify-content: space-between; 65 | } 66 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import imagemin from "imagemin"; 2 | import imageminWebp from "imagemin-webp"; 3 | import path from "path"; 4 | import { defineConfig } from "vite"; 5 | import glob from "fast-glob"; 6 | import { fileURLToPath } from "url"; 7 | import { ViteImageOptimizer } from "vite-plugin-image-optimizer"; 8 | 9 | export default defineConfig({ 10 | plugins: [ 11 | ViteImageOptimizer({ 12 | png: { 13 | quality: 86, 14 | }, 15 | jpeg: { 16 | quality: 86, 17 | }, 18 | jpg: { 19 | quality: 86, 20 | }, 21 | }), 22 | { 23 | ...imagemin(["./src/img/**/*.{jpg,png,jpeg}"], { 24 | destination: "./src/img/webp/", 25 | plugins: [imageminWebp({ quality: 86 })], 26 | }), 27 | apply: "serve", 28 | }, 29 | ], 30 | build: { 31 | minify: false, // disable minification 32 | rollupOptions: { 33 | input: Object.fromEntries( 34 | glob 35 | .sync(["./*.html", "./pages/**/*.html"]) 36 | .map((file) => [ 37 | path.relative(__dirname, file.slice(0, file.length - path.extname(file).length)), 38 | fileURLToPath(new URL(file, import.meta.url)), 39 | ]) 40 | ), 41 | // output unminified CSS file 42 | output: { 43 | assetFileNames: "assets/[name].[ext]", 44 | }, 45 | }, 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /src/scss/layout/_main.scss: -------------------------------------------------------------------------------- 1 | @use "../utilities/mixins"; 2 | 3 | .main { 4 | flex: 1; 5 | &-header { 6 | padding: 2.5rem 2rem; 7 | } 8 | 9 | &-logo { 10 | width: 300px; 11 | height: 300px; 12 | display: inline-block; 13 | position: relative; 14 | margin-bottom: 3rem; 15 | 16 | @include mixins.viewport-md { 17 | width: 360px; 18 | height: 360px; 19 | } 20 | 21 | &::before { 22 | content: ""; 23 | position: absolute; 24 | z-index: -1; 25 | top: 50%; 26 | left: 50%; 27 | width: 70%; 28 | height: 70%; 29 | transform: translate(-50%, -50%); 30 | border-radius: 50%; 31 | background: var(--hero-name-background); 32 | filter: blur(72px); 33 | } 34 | } 35 | 36 | &-logo-img { 37 | width: 100%; 38 | height: 100%; 39 | } 40 | 41 | &-title { 42 | &-link { 43 | position: relative; 44 | transition: 200ms ease; 45 | 46 | &::before { 47 | content: ""; 48 | position: absolute; 49 | bottom: 5px; 50 | left: 50%; 51 | transform: translateX(-50%) skewX(-10deg); 52 | z-index: -1; 53 | 54 | width: 105%; 55 | height: 20%; 56 | background-color: var(--brand-light-color); 57 | 58 | transition: 200ms ease; 59 | } 60 | 61 | &:hover, 62 | &:focus { 63 | color: var(--brand-light-color); 64 | 65 | &::before { 66 | background-color: var(--main-text-color); 67 | } 68 | } 69 | } 70 | } 71 | 72 | &-badges { 73 | margin: 3rem 0 5rem; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-12/_decimal.scss: -------------------------------------------------------------------------------- 1 | // _decimal.scss | MIT License | gist.github.com/terkel/4373420 2 | 3 | // Round a number to specified digits. 4 | // 5 | // @param {Number} $number A number to round 6 | // @param {Number} [$digits:0] Digits to output 7 | // @param {String} [$mode:round] (round|ceil|floor) How to round a number 8 | // @return {Number} A rounded number 9 | // @example 10 | // decimal-round(0.333) => 0 11 | // decimal-round(0.333, 1) => 0.3 12 | // decimal-round(0.333, 2) => 0.33 13 | // decimal-round(0.666) => 1 14 | // decimal-round(0.666, 1) => 0.7 15 | // decimal-round(0.666, 2) => 0.67 16 | // 17 | @use "sass:math"; 18 | 19 | @function decimal-round($number, $digits: 0, $mode: round) { 20 | $n: 1; 21 | // $number must be a number 22 | @if type-of($number) != number { 23 | @warn '#{ $number } is not a number.'; 24 | @return $number; 25 | } 26 | // $digits must be a unitless number 27 | @if type-of($digits) != number { 28 | @warn '#{ $digits } is not a number.'; 29 | @return $number; 30 | } @else if not unitless($digits) { 31 | @warn '#{ $digits } has a unit.'; 32 | @return $number; 33 | } 34 | @if $digits > 0 { 35 | @for $i from 1 through $digits { 36 | $n: $n * 10; 37 | } 38 | } 39 | @if $mode == round { 40 | @return math.div(math.round($number * $n), $n); 41 | } @else if $mode == ceil { 42 | @return math.div(math.ceil($number * $n), $n); 43 | } @else if $mode == floor { 44 | @return math.div(math.floor($number * $n), $n); 45 | } @else { 46 | @warn '#{ $mode } is undefined keyword.'; 47 | @return $number; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/img/icons/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/img/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/project-structure.md: -------------------------------------------------------------------------------- 1 | ```scss 2 | sass/ 3 | | 4 | ├── base/ 5 | | ├── _base.scss // # Набір базових стилей 6 | | ├── _reset.scss // # Скидання стилей браузера 7 | | ├── _typography.scss // # Текстові стилі 8 | | ├── _animations.scss // # Анімації (додані через @keyframes) 9 | | … // # і таке інше 10 | | 11 | ├── components/ 12 | | ├── _buttons.scss // # Кнопки 13 | | ├── _carousel.scss // # Слайдер 14 | | ├── _cover.scss // # Обкладинка 15 | | ├── _dropdown.scss // # Випадаюче меню 16 | | … // # і таке інше 17 | | 18 | ├── layout/ 19 | | ├── _navigation.scss // # Навігація 20 | | ├── _grid.scss // # Сітка 21 | | ├── _header.scss // # Хедер 22 | | ├── _footer.scss // # Футер 23 | | ├── _sidebar.scss // # Сайдбар 24 | | ├── _forms.scss // # Форми 25 | | … // # і таке інше 26 | | 27 | ├── pages/ 28 | | ├── _home.scss // # Специфічні стилі сторінки Home 29 | | ├── _contact.scss // # Специфічні стилі сторінки Contact 30 | | … // # і таке інше 31 | | 32 | ├── themes/ 33 | | ├── _theme.scss // # Тема за змовчуванням 34 | | ├── _admin.scss // # Тема для адміністратора сайту 35 | | ├── _manager.scss // # Тема для менеджера сайту 36 | | … // # і таке інше 37 | | 38 | ├── vendors/ 39 | | ├── _bootstrap.scss // # Bootstrap бібліотека 40 | | ├── _modern-normalize.scss // # Нормалізація стилей 41 | | … // # і таке інше 42 | | 43 | ├── utils/ 44 | | ├── _variables.scss // # Sass змінні 45 | | ├── _functions.scss // # Sass функції 46 | | ├── _mixins.scss // # Sass міксини 47 | | ├── _placeholders.scss // # Sass плейсхолдери 48 | | 49 | └── main.scss // # Головний Sass файл 50 | ``` 51 | -------------------------------------------------------------------------------- /src/img/icons/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-09/_extend.scss: -------------------------------------------------------------------------------- 1 | // $primary: #f07f2e; 2 | // $success: #82c43c; 3 | // $primary: #4e75ff; 4 | 5 | // Approach 1 6 | // .notification { 7 | // display: flex; 8 | // align-items: center; 9 | // gap: 20px; 10 | 11 | // width: 480px; 12 | // padding: 20px; 13 | 14 | // font-family: Montserrat; 15 | // color: #fafafb; 16 | // font-size: 16px; 17 | // line-height: 20px; /* 125% */ 18 | // letter-spacing: 0.5px; 19 | 20 | // background-color: #92929d; 21 | // border-radius: 6px; 22 | // } 23 | // .notification-primary { 24 | // background-color: #f07f2e; 25 | // } 26 | 27 | // .notification-success { 28 | // background-color: #82c43c; 29 | // } 30 | 31 | // .notification-info { 32 | // background-color: #4e75ff; 33 | // } 34 | 35 | // Approach 2 36 | // .notification { 37 | // display: flex; 38 | // align-items: center; 39 | // gap: 20px; 40 | 41 | // width: 480px; 42 | // padding: 20px; 43 | 44 | // font-family: Montserrat; 45 | // color: #fafafb; 46 | // font-size: 16px; 47 | // line-height: 20px; /* 125% */ 48 | // letter-spacing: 0.5px; 49 | 50 | // background-color: #92929d; 51 | // border-radius: 6px; 52 | // } 53 | 54 | // .notification-primary { 55 | // @extend .notification; 56 | 57 | // background-color: #f07f2e; 58 | // } 59 | 60 | // .notification-success { 61 | // @extend .notification; 62 | 63 | // background-color: #82c43c; 64 | // } 65 | 66 | // .notification-info { 67 | // @extend .notification; 68 | 69 | // background-color: #4e75ff; 70 | // } 71 | 72 | // Approach 3 73 | %notification { 74 | display: flex; 75 | align-items: center; 76 | gap: 20px; 77 | 78 | width: 480px; 79 | padding: 20px; 80 | 81 | font-family: Montserrat; 82 | color: #fafafb; 83 | font-size: 16px; 84 | line-height: 20px; /* 125% */ 85 | letter-spacing: 0.5px; 86 | 87 | background-color: #92929d; 88 | border-radius: 6px; 89 | } 90 | 91 | .notification-primary { 92 | @extend %notification; 93 | 94 | background-color: #f07f2e; 95 | } 96 | 97 | .notification-success { 98 | @extend %notification; 99 | 100 | background-color: #82c43c; 101 | } 102 | 103 | .notification-info { 104 | @extend %notification; 105 | 106 | background-color: #4e75ff; 107 | } 108 | -------------------------------------------------------------------------------- /src/img/icons/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/img/icons/danger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/scss/base/_reset.scss: -------------------------------------------------------------------------------- 1 | /*** 2 | The new CSS reset - version 1.11 (last updated 20.9.2023) 3 | GitHub page: https://github.com/elad2412/the-new-css-reset 4 | ***/ 5 | 6 | /* 7 | Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property 8 | - The "symbol *" part is to solve Firefox SVG sprite bug 9 | - The "html" element is excluded, otherwise a bug in Chrome breaks the CSS hyphens property (https://github.com/elad2412/the-new-css-reset/issues/36) 10 | */ 11 | *:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) { 12 | all: unset; 13 | display: revert; 14 | } 15 | 16 | /* Preferred box-sizing value */ 17 | *, 18 | *::before, 19 | *::after { 20 | box-sizing: border-box; 21 | } 22 | 23 | /* Fix mobile Safari increase font-size on landscape mode */ 24 | html { 25 | -moz-text-size-adjust: none; 26 | -webkit-text-size-adjust: none; 27 | text-size-adjust: none; 28 | } 29 | 30 | /* Reapply the pointer cursor for anchor tags */ 31 | a, 32 | button { 33 | cursor: revert; 34 | } 35 | 36 | /* Remove list styles (bullets/numbers) */ 37 | ol, 38 | ul, 39 | menu { 40 | list-style: none; 41 | } 42 | 43 | /* For images to not be able to exceed their container */ 44 | img { 45 | max-inline-size: 100%; 46 | max-block-size: 100%; 47 | } 48 | 49 | /* removes spacing between cells in tables */ 50 | table { 51 | border-collapse: collapse; 52 | } 53 | 54 | /* Safari - solving issue when using user-select:none on the text input doesn't working */ 55 | input, 56 | textarea { 57 | -webkit-user-select: auto; 58 | } 59 | 60 | /* revert the 'white-space' property for textarea elements on Safari */ 61 | textarea { 62 | white-space: revert; 63 | } 64 | 65 | /* minimum style to allow to style meter element */ 66 | meter { 67 | -webkit-appearance: revert; 68 | appearance: revert; 69 | } 70 | 71 | /* preformatted text - use only for this feature */ 72 | :where(pre) { 73 | all: revert; 74 | box-sizing: border-box; 75 | } 76 | 77 | /* reset default text opacity of input placeholder */ 78 | ::placeholder { 79 | color: unset; 80 | } 81 | 82 | /* remove default dot (•) sign */ 83 | ::marker { 84 | content: initial; 85 | } 86 | 87 | /* fix the feature of 'hidden' attribute. 88 | display:revert; revert to element instead of attribute */ 89 | :where([hidden]) { 90 | display: none; 91 | } 92 | 93 | /* revert for bug in Chromium browsers 94 | - fix for the content editable attribute will work properly. 95 | - webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element*/ 96 | :where([contenteditable]:not([contenteditable="false"])) { 97 | -moz-user-modify: read-write; 98 | -webkit-user-modify: read-write; 99 | overflow-wrap: break-word; 100 | -webkit-line-break: after-white-space; 101 | -webkit-user-select: auto; 102 | } 103 | 104 | /* apply back the draggable feature - exist only in Chromium and Safari */ 105 | :where([draggable="true"]) { 106 | -webkit-user-drag: element; 107 | } 108 | 109 | /* Revert Modal native behavior */ 110 | :where(dialog:modal) { 111 | all: revert; 112 | box-sizing: border-box; 113 | } 114 | -------------------------------------------------------------------------------- /src/scss/--examples--/lesson-10/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin frame-size($width, $height: $width) { 2 | width: $width; 3 | height: $height; 4 | } 5 | 6 | %size { 7 | width: 150px; 8 | height: 150px; 9 | } 10 | 11 | .avatar { 12 | @include frame-size(150px); 13 | @extend %size; 14 | 15 | border-radius: 50%; 16 | } 17 | 18 | .icon { 19 | @include frame-size(50px); 20 | @extend %size; 21 | 22 | border: 2px solid lightblue; 23 | } 24 | 25 | // Arguments 26 | @mixin position-center { 27 | position: absolute; 28 | top: 50%; 29 | left: 50%; 30 | transform: translate(-50%, -50%); 31 | } 32 | 33 | .decoration { 34 | @include position-center; 35 | } 36 | 37 | @mixin position($position-type, $position-x, $position-y, $offset-x, $offset-y) { 38 | position: $position-type; 39 | top: $position-y; 40 | left: $position-x; 41 | transform: translate($offset-x, $offset-y); 42 | } 43 | 44 | .decoration { 45 | @include position(absolute, 50%, 50%, -50%, -50%); 46 | } 47 | 48 | @mixin position( 49 | $layer-index, 50 | $display, 51 | // обовʼязковий параметр 52 | $position-type: absolute, 53 | $position-x: 50%, 54 | $position-y: $position-x, 55 | $offset-x: $position-x, 56 | $offset-y: $position-x 57 | ) { 58 | position: $position-type; 59 | top: $position-y; 60 | left: $position-x; 61 | transform: translate(($offset-x * -1), ($offset-y * -1)); 62 | z-index: $layer-index; 63 | display: $display; 64 | } 65 | 66 | .decoration { 67 | @include position($offset-y: 70%, $layer-index: 100, $display: block); 68 | } 69 | 70 | %btn { 71 | font-family: Montserrat; 72 | font-size: 14px; 73 | font-weight: 500; 74 | line-height: 20px; /* 142.857% */ 75 | letter-spacing: 0.5px; 76 | color: #fafafb; 77 | 78 | background-color: #f07f2e; 79 | border: none; 80 | cursor: pointer; 81 | transition: 300ms; 82 | 83 | &:hover, 84 | &:focus { 85 | background-color: #f15c27; 86 | box-shadow: 0px 4px 10px 0px rgba(240, 127, 46, 0.25); 87 | } 88 | } 89 | 90 | @mixin btn-size($args...) { 91 | @for $i from 1 through length($args) { 92 | #{nth($args, $i)} { 93 | $factor: ($i * 4 - 4); 94 | 95 | @extend %btn; 96 | 97 | padding: (4px + $factor) (8px + $factor); 98 | border-radius: (8px + $factor); 99 | } 100 | } 101 | } 102 | 103 | @include btn-size(".btn-sm", ".btn-md", ".btn-lg", ".btn-xl"); 104 | 105 | @use "sass:meta"; 106 | 107 | @mixin btn-type($types...) { 108 | // $types: ( 109 | // $success: lightgreen, 110 | // $error: tomato, 111 | // $info: lightblue, 112 | // ); 113 | 114 | @each $name, $color in meta.keywords($types) { 115 | .btn-#{$name} { 116 | border: 2px solid $color; 117 | color: $color; 118 | } 119 | } 120 | } 121 | 122 | @include btn-type($success: lightgreen, $error: tomato, $info: lightblue); 123 | 124 | @mixin hover($state) { 125 | &:not([#{$state}]):hover { 126 | @content; 127 | } 128 | } 129 | 130 | .button { 131 | background-color: white; 132 | border: 1px solid darkblue; 133 | 134 | @include hover($state: disabled) { 135 | color: white; 136 | background-color: darkblue; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/img/icons.svg: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple starter template for Sass 2 | 3 | ![screenshot](./demo/main-page.jpg) 4 | 5 | ## Vanilla App Template 6 | 7 | Цей проект було створено за допомогою Vite. Для знайомства та налаштування 8 | додаткових можливостей [звернись до документації](https://vitejs.dev/). 9 | 10 | Ключові особливості цього шаблону: 11 | 12 | **Build Tools:** Vite.js 13 | **Plugins:** Autoprefixer, PostCSS Sort Media Queries 14 | **Styles:** SCSS 15 | **Reset:** \_reset.scss (Based on The New Reset CSS) 16 | 17 | ## Створення репозиторію за шаблоном 18 | 19 | Використовуй цей репозиторій організації GoIT як шаблон для створення 20 | репозиторію свого проекту. Для цього натисни на кнопку `«Use this template»` і 21 | обери опцію `«Create a new repository»`, як показано на зображенні. 22 | 23 | ![Creating repo from a template step 1](./demo/template-step-1.png) 24 | 25 | На наступному етапі відкриється сторінка створення нового репозиторію. Заповни 26 | поле його імені, переконайся, що репозиторій публічний, після чого натисни 27 | кнопку `«Create repository from template»`. 28 | 29 | ![Creating repo from a template step 2](./demo/template-step-2.png) 30 | 31 | Після того, як репозиторій буде створено, необхідно перейти в налаштування 32 | створеного репозиторію на вкладку `Settings` > `Actions` > `General` як показано 33 | на зображенні. 34 | 35 | ![Settings GitHub Actions permissions step 1](./demo/gh-actions-perm-1.png) 36 | 37 | Проскроливши сторінку до самого кінця, в секції `«Workflow permissions»` обери 38 | опцію `«Read and write permissions»` і постав галочку в чекбоксі. Це необхідно 39 | для автоматизації процесу деплою проекту. 40 | 41 | ![Settings GitHub Actions permissions step 2](./demo/gh-actions-perm-2.png) 42 | 43 | Тепер у тебе є особистий репозиторій проекту, зі структурою файлів та папок 44 | репозиторію-шаблону. Далі працюй з ним, як з будь-яким іншим особистим 45 | репозиторієм, клонуй його собі на комп'ютер, пиши код, роби коміти та відправляй 46 | їх на GitHub! 47 | 48 | ## Підготовка до роботи 49 | 50 | 1. Переконайся, що на комп'ютері встановлено LTS-версію Node.js. 51 | [Скачай та встанови](https://nodejs.org/en/) її якщо необхідно. 52 | 2. Встанови базові залежності проекту в терміналі командою `npm install`. 53 | 3. Запусти режим розробки, виконавши в терміналі команду `npm run dev`. 54 | 4. Перейдіть у браузері за адресою 55 | [http://localhost:5173](http://localhost:5173). Ця сторінка буде автоматично 56 | перезавантажуватись після збереження змін у файли проекту. 57 | 5. Для перегляду результуючого СSS файлу виконай команду 58 | `npx vite build --watch` та перейди в папку `dist/assets` 59 | 60 | ## Структура проекту. Файли і папки 61 | 62 | This is the structure of the project: 63 | 64 | ```plaintext 65 | / 66 | ├── demo # Папка для файлів цієї інструкції 67 | ├── dist # Результуючий код 68 | ├── node_modules # Node.js залежності для проекту 69 | ├── public # Файли для публічного доступу та використання 70 | ├── src # Вихідний код 71 | │ ├── fonts # Папка для ваших шрифтів 72 | │ ├── img # Папка для ваших зображень 73 | │ ├── js # Файли Javascript вашого проекту 74 | │ ├── scss # Стилі SCSS для вашого проекту 75 | ├── .gitignore # Перелік файлів та папок, які ігнорує Git 76 | ├── index.html # Файл HTML для вашого проекту 77 | ├── LICENSE # Файл ліцензії для вашого проекту 78 | ├── package-lock.json # Файл з поточними версіями залежностей для вашого проекту 79 | ├── package.json # Визначає метадані вашого проекту і його залежності 80 | ├── postcss.config.cjs # Конфігурація для PostCSS 81 | ├── README.md # Цей файл 😎 82 | ├── vite.config.js # Конфігурація бандлера Vite 83 | ``` 84 | 85 | ## Подальші кроки 86 | 87 | Після клонування шаблону обов’язково очистіть і оновіть наступні файли/папки: 88 | 89 | 1. Очистіть файл README.md. 90 | 2. Адаптуйте файл LICENSE до свого проекту. 91 | 3. Очистіть `public/sass.svg`, папки `demo/`, `src/img/**/*`, `src/fonts/**/*`, а також `src/scss/**.*`, окрім файлів `style.scss` та `_reset.scss`. 92 | 4. Видаліть вміст із файлу `src/scss/style.scss`, окрім `@use "reset.scss";`. 93 | 5. У файлі `src/js/main.js`, залиште лише цей рядок з імпортом: `import '../scss/style.scss';`. 94 | 95 | ## Деплой 96 | 97 | Продакшн версія проекту буде автоматично збиратися та деплоїтись на GitHub 98 | Pages, у гілку `gh-pages`, щоразу, коли оновлюється гілка `main`. Наприклад, 99 | після прямого пуша або прийнятого пул-реквесту. Для цього необхідно у файлі 100 | `package.json` змінити значення прапора `--base=//`, для команди `build`, 101 | замінивши `` на назву свого репозиторію, та відправити зміни на GitHub. 102 | 103 | ```json 104 | "build": "vite build --base=//", 105 | ``` 106 | 107 | Далі необхідно зайти в налаштування GitHub-репозиторію (`Settings` > `Pages`) та 108 | виставити роздачу продакшн версії файлів з папки `/root` гілки `gh-pages`, якщо 109 | це не було зроблено автоматично. 110 | 111 | ![GitHub Pages settings](./demo/repo-settings.png) 112 | 113 | ## License 114 | 115 | Цей шаблон створено під [MIT License](LICENSE). 116 | 117 | **Thank you and happy coding!** 💻 118 | -------------------------------------------------------------------------------- /public/sass.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | --------------------------------------------------------------------------------