diff options
| author | Armand Philippot <git@armandphilippot.com> | 2021-10-30 22:11:00 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2021-10-30 22:52:23 +0200 |
| commit | 3a3baddad1c801d77dc398d2c6980f3c14f4a47c (patch) | |
| tree | 9e06aef730504470111c010e53a1857f7b01ab83 /src/scss | |
| parent | c3045b163e74b42c0a0e71c646740c76d3bb5ba1 (diff) | |
chore: move htdocs to repo root
Diffstat (limited to 'src/scss')
25 files changed, 1173 insertions, 0 deletions
diff --git a/src/scss/abstracts/_functions.scss b/src/scss/abstracts/_functions.scss new file mode 100644 index 0000000..672e5e7 --- /dev/null +++ b/src/scss/abstracts/_functions.scss @@ -0,0 +1,4 @@ +@forward "./functions/convert"; +@forward "./functions/css-vars"; +@forward "./functions/str-replace"; +@forward "./functions/encode"; diff --git a/src/scss/abstracts/_mixins.scss b/src/scss/abstracts/_mixins.scss new file mode 100644 index 0000000..fd28631 --- /dev/null +++ b/src/scss/abstracts/_mixins.scss @@ -0,0 +1,2 @@ +@forward "./mixins/css-vars"; +@forward "./mixins/media-queries"; diff --git a/src/scss/abstracts/_placeholders.scss b/src/scss/abstracts/_placeholders.scss new file mode 100644 index 0000000..079cae7 --- /dev/null +++ b/src/scss/abstracts/_placeholders.scss @@ -0,0 +1,32 @@ +/// List Reset +%reset-list { + list-style-type: none; + margin: 0; + padding: 0; + + li { + margin-bottom: 0; + } +} + +/// Ordered List Reset +%reset-ordered-list { + @extend %reset-list; + + li { + counter-increment: none; + display: list-item; + + &::before { + display: none; + } + } +} + +/// Display an inline list with flexbox +%flex-list { + @extend %reset-list; + + display: flex; + flex-flow: row wrap; +} diff --git a/src/scss/abstracts/_variables.scss b/src/scss/abstracts/_variables.scss new file mode 100644 index 0000000..a8a22a8 --- /dev/null +++ b/src/scss/abstracts/_variables.scss @@ -0,0 +1,103 @@ +@use "sass:math"; +@use "../abstracts/functions" as fun; + +//=========================================================================== +// Ratios +//=========================================================================== + +/// Ratios map +/// @prop {String} keys - Keys are identifiers mapped to a given ratio +/// @prop {Map} value - Value is actual ratio +$ratios: ( + "minor-second": 1.067, + "major-second": 1.125, + "minor-third": 1.2, + "major-third": 1.25, + "perfect-fourth": 1.333, + "augmented-fourth": 1.414, + "perfect-fifth": 1.5, + "golden-number": 1.618, +); + +// Cannot declare the following function in partials due to module loop. +// Also, it will only be used in this file so it is not a problem. + +/// Get ratio +/// @param {String} $name - Ratio name. +/// @return {Integer} The ratio value. +@function get-ratio($name) { + @return map-get($ratios, $name); +} + +//=========================================================================== +// Layout +//=========================================================================== + +/// Breakpoints map +/// @prop {String} keys - Keys are identifiers mapped to a given length +/// @prop {Map} values - Values are actual breakpoints expressed in pixels +$breakpoints: ( + "xs": fun.convert-px(568, "em"), + "sm": fun.convert-px(768, "em"), + "md": fun.convert-px(1024, "em"), + "lg": fun.convert-px(1200, "em"), + "xl": fun.convert-px(1600, "em"), + "2xl": fun.convert-px(1920, "em"), +); + +//=========================================================================== +// Fonts +//=========================================================================== + +/* stylelint-disable -- Fonts name are not keywords, lowercase is not needed. */ +/// Regular font family +/// @type List +$font-family_primary: ("Inter", "Liberation Sans", Arial, sans-serif); + +/// Alternative regular font family +/// @type List +$font-family_secondary: ("Kanit", "Liberation Sans", Arial, sans-serif); + +$line-height: get-ratio("golden-number"); + +$font-size_base: 16px; +$font-size_base-rem: fun.convert-px(16); // font-size_base without unit +$font-size_ratio: get-ratio("minor-third"); +$font-size_sm: $font-size_base-rem * math.pow($font-size_ratio, -1); +$font-size_md: $font-size_base-rem * math.pow($font-size_ratio, 0); +$font-size_lg: $font-size_base-rem * math.pow($font-size_ratio, 1); +$font-size_xl: $font-size_base-rem * math.pow($font-size_ratio, 2); +$font-size_2xl: $font-size_base-rem * math.pow($font-size_ratio, 3); +$font-size_3xl: $font-size_base-rem * math.pow($font-size_ratio, 4); + +//============================================================================ +// Spacings +//============================================================================ + +$spacing_ratio: get-ratio("golden-number"); +$spacing_base: $spacing_ratio * 1rem; + +$spacing_3xs: math.div($spacing_base, 4); +$spacing_2xs: math.div($spacing_base, 3); +$spacing_xs: math.div($spacing_base, 2); +$spacing_sm: math.div($spacing_base, 1.5); +$spacing_md: $spacing_base; +$spacing_lg: $spacing_base * 1.5; + +//============================================================================ +// Colors +//============================================================================ + +$color_black-squeeze: hsl(212, 55%, 97%); +$color_catskill-white: hsl(212, 53%, 92%); +$color_link-water: hsl(212, 51%, 87%); +$color_geyser: hsl(212, 27%, 83%); +$color_gull-gray: hsl(212, 15%, 66%); +$color_pale-sky: hsl(212, 13%, 46%); +$color_nile-blue: hsl(212, 47%, 19%); +$color_firefly: hsl(212, 45%, 11%); +$color_chambray: hsl(212, 45%, 40%); +$color_chathams-blue: hsl(212, 65%, 28%); +$color_chathams-blue-light: hsl(212, 90%, 30%); +$color_chathams-blue-light-opacity-25: hsla(212, 90%, 30%, 0.25); +$color_chathams-blue-dark: hsl(212, 70%, 25%); diff --git a/src/scss/abstracts/functions/_convert.scss b/src/scss/abstracts/functions/_convert.scss new file mode 100644 index 0000000..9f51dc7 --- /dev/null +++ b/src/scss/abstracts/functions/_convert.scss @@ -0,0 +1,16 @@ +@use "sass:math"; + +/// Convert px to rem or em. +/// @param {Number} $px Value in px +/// @param {String} $to Unit. Either "rem" or "em" +/// @param {Number} $standard 1rem (or 1em) = 16px +/// @return {Number} Value in rem or em +@function convert-px($px, $to: "rem", $standard: 16) { + @if $to == "rem" { + @return math.div($px, $standard) + 0rem; // stylelint-disable-line + } @else if $to == "em" { + @return math.div($px, $standard) + 0em; // stylelint-disable-line + } @else { + @error "`$to` must be either `rem` or `em`."; + } +} diff --git a/src/scss/abstracts/functions/_css-vars.scss b/src/scss/abstracts/functions/_css-vars.scss new file mode 100644 index 0000000..89e1a15 --- /dev/null +++ b/src/scss/abstracts/functions/_css-vars.scss @@ -0,0 +1,8 @@ +/// Retrieve a CSS variable value with prefix +/// @see https://dev.to/felipperegazio/css-custom-properties-vars-with-sass-scss-a-practical-architecture-strategy-1m88 +/// @param {String} $name Variable name +/// @param {String} $prefix Variable prefix +/// @return {String} Variable in CSS format +@function get-var($name, $prefix: dap) { + @return var(--#{$prefix}-#{$name}); +} diff --git a/src/scss/abstracts/functions/_encode.scss b/src/scss/abstracts/functions/_encode.scss new file mode 100644 index 0000000..4350185 --- /dev/null +++ b/src/scss/abstracts/functions/_encode.scss @@ -0,0 +1,14 @@ +@use "str-replace" as fun; + +/// Encode a SVG. +/// @param {String} $svg A complete svg (`<svg>...</svg>`). +/// @return The encoded svg, ready to use for background-image. +@function encode-svg($svg) { + $svg-encoding: (("<", "%3C"), (">", "%3E"), ("#", "%23")); + + @each $char, $encoded in $svg-encoding { + $svg: fun.str-replace($svg, $char, $encoded); + } + + @return "data:image/svg+xml;utf8," + $svg; +} diff --git a/src/scss/abstracts/functions/_str-replace.scss b/src/scss/abstracts/functions/_str-replace.scss new file mode 100644 index 0000000..624bf33 --- /dev/null +++ b/src/scss/abstracts/functions/_str-replace.scss @@ -0,0 +1,20 @@ +/// Replace `$search` with `$replace` in `$string` +/// @author Hugo Giraudel +/// @param {String} $string - Initial string +/// @param {String} $search - Substring to replace +/// @param {String} $replace ('') - New value +/// @return {String} - Updated string +@function str-replace($string, $search, $replace: "") { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + + str-replace( + str-slice($string, $index + str-length($search)), + $search, + $replace + ); + } + + @return $string; +} diff --git a/src/scss/abstracts/mixins/_css-vars.scss b/src/scss/abstracts/mixins/_css-vars.scss new file mode 100644 index 0000000..8e31c96 --- /dev/null +++ b/src/scss/abstracts/mixins/_css-vars.scss @@ -0,0 +1,20 @@ +/// Declare a set of CSS variables properly prefixed. +/// +/// @see https://dev.to/felipperegazio/css-custom-properties-vars-with-sass-scss-a-practical-architecture-strategy-1m88 +/// +/// @param {List} $variables - A list of variable name and value. +/// @param {Bool} $root - Set vars at root. +/// @param {String} $prefix - The variables prefix. +@mixin set-vars($variables, $root: true, $prefix: "dap") { + @if $root { + :root { + @each $name, $value in $variables { + --#{$prefix}-#{$name}: #{$value}; + } + } + } @else { + @each $name, $value in $variables { + --#{$prefix}-#{$name}: #{$value}; + } + } +} diff --git a/src/scss/abstracts/mixins/_media-queries.scss b/src/scss/abstracts/mixins/_media-queries.scss new file mode 100644 index 0000000..fcaea4b --- /dev/null +++ b/src/scss/abstracts/mixins/_media-queries.scss @@ -0,0 +1,81 @@ +@use "../variables" as var; + +/// Media query: media type +/// @param {String} $type - Media type: all, screen, print, retina. +/// @example scss - `@media only screen` equivalent is: +/// @include media("screen"); +@mixin media($type) { + @if $type == "retina" { + $type: "(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)"; + } @else if $type == "screen" or $type == "print" { + $type: "only #{$type}"; + } + + @media #{$type} { + @content; + } +} + +/// Media query: min-width / max-width +/// @param {String} $from - min-width breakpoint. +/// @param {String} $until - max-width breakpoint. +/// @example scss - `@media (min-width: "md")` equivalent is: +/// @include dimensions("md"); +@mixin dimensions($from: null, $until: null) { + $query: ""; + + @if $from { + @if type-of($from) == "string" { + $size: map-get(var.$breakpoints, $from); + $query: "(min-width: #{$size})"; + } @else { + @error "`$from` must be a string."; + } + } + + @if $from and $until { + $query: $query + " and "; + } + + @if $until { + @if type-of($until) == "string" { + $size: map-get(var.$breakpoints, $until); + $size: calc(#{$size} - 1px); + $query: $query + "(max-width: #{$size})"; + } @else { + @error "`$until` must be a string."; + } + } + + @media #{$query} { + @content; + } +} + +/// Media query: prefers-reduced-motion +/// @param {String} $value - Media query value: `no-preference` or `reduce`. +/// @example scss - @media (prefers-reduced-motion: "reduce") equivalent is: +/// @include motion("reduce"); +@mixin motion($value) { + @if $value == "no-preference" or $value == "reduce" { + @media (prefers-reduced-motion: #{$value}) { + @content; + } + } @else { + @error "Allowed values are `no-preference` and `reduce`."; + } +} + +/// Media query: any-pointer +/// @param {String} $value - Media query value: `fine`, `coarse` or `none`. +/// @example scss - @media (any-pointer: "fine") equivalent is: +/// @include pointer("fine"); +@mixin pointer($value) { + @if $value == "fine" or $value == "coarse" or $value == "none" { + @media (any-pointer: #{$value}) { + @content; + } + } @else { + @error "Allowed values are `fine`, `coarse` and `none`."; + } +} diff --git a/src/scss/base/_animations.scss b/src/scss/base/_animations.scss new file mode 100644 index 0000000..a2df8ab --- /dev/null +++ b/src/scss/base/_animations.scss @@ -0,0 +1,89 @@ +@keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + visibility: visible; + } +} + +@keyframes fadeOut { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + visibility: hidden; + } +} + +@keyframes slideInLeft { + 0% { + margin-left: -100%; + } + + 100% { + margin-left: 0; + visibility: visible; + } +} + +@keyframes slideOutLeft { + 0% { + margin-left: 0; + } + + 100% { + margin-left: -100%; + visibility: hidden; + } +} + +@keyframes slideInUp { + 0% { + margin-bottom: -100vh; + } + + 100% { + margin-bottom: 0; + visibility: visible; + } +} + +@keyframes slideOutBottom { + 0% { + margin-bottom: 0; + } + + 100% { + margin-bottom: -100vh; + visibility: hidden; + } +} + +.fade-in { + animation: fadeIn 1s; +} + +.fade-out { + animation: fadeOut 1s; +} + +.slide-in--left { + animation: slideInLeft 0.8s; +} + +.slide-out--left { + animation: slideOutLeft 0.8s; +} + +.slide-in--up { + animation: slideInUp 1s; +} + +.slide-out--bottom { + animation: slideOutBottom 1s; +} diff --git a/src/scss/base/_base.scss b/src/scss/base/_base.scss new file mode 100644 index 0000000..a157a50 --- /dev/null +++ b/src/scss/base/_base.scss @@ -0,0 +1,3 @@ +html { + overflow: hidden; +} diff --git a/src/scss/base/_colors.scss b/src/scss/base/_colors.scss new file mode 100644 index 0000000..6251b2e --- /dev/null +++ b/src/scss/base/_colors.scss @@ -0,0 +1,21 @@ +@use "../abstracts/mixins" as mix; +@use "../abstracts/variables" as var; +@include mix.set-vars( + ( + color-bg: #{var.$color_black-squeeze}, + color-bg-secondary: #{var.$color_catskill-white}, + color-bg-tertiary: #{var.$color_link-water}, + color-fg: #{var.$color_firefly}, + color-fg-inverted: #{var.$color_black-squeeze}, + color-border: #{var.$color_chathams-blue}, + color-border-light: #{var.$color_geyser}, + color-shadow-darker: #{var.$color_nile-blue}, + color-shadow-dark: #{var.$color_pale-sky}, + color-shadow: #{var.$color_chambray}, + color-shadow-light: #{var.$color_gull-gray}, + color-primary: #{var.$color_chathams-blue}, + color-primary-light: #{var.$color_chathams-blue-light}, + color-primary-light-opacity: #{var.$color_chathams-blue-light-opacity-25}, + color-primary-dark: #{var.$color_chathams-blue-dark}, + ) +); diff --git a/src/scss/base/_fonts.scss b/src/scss/base/_fonts.scss new file mode 100644 index 0000000..192f6b8 --- /dev/null +++ b/src/scss/base/_fonts.scss @@ -0,0 +1,115 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; +@use "../abstracts/variables" as var; + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 700; + src: url("../fonts/Kanit/Kanit-Bold.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Bold.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 700; + src: url("../fonts/Kanit/Kanit-BoldItalic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-BoldItalic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 600; + src: url("../fonts/Kanit/Kanit-SemiBold.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-SemiBold.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 600; + src: url("../fonts/Kanit/Kanit-SemiBoldItalic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-SemiBoldItalic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 500; + src: url("../fonts/Kanit/Kanit-Medium.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Medium.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 500; + src: url("../fonts/Kanit/Kanit-MediumItalic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-MediumItalic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 400; + src: url("../fonts/Kanit/Kanit-Regular.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Regular.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 400; + src: url("../fonts/Kanit/Kanit-Italic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Italic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 300; + src: url("../fonts/Kanit/Kanit-Light.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Light.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 300; + src: url("../fonts/Kanit/Kanit-LightItalic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-LightItalic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Inter; + font-style: oblique 0deg 10deg; + font-weight: 100 900; + src: url("../fonts/Inter/Inter.woff2?v=3.18") format("woff2"); +} + +@include mix.set-vars( + ( + font-family-primary: #{var.$font-family_primary}, + font-family-secondary: #{var.$font-family_secondary}, + font-size-sm: #{var.$font-size_sm}, + font-size-md: #{var.$font-size_md}, + font-size-lg: #{var.$font-size_lg}, + font-size-xl: #{var.$font-size_xl}, + font-size-2xl: #{var.$font-size_2xl}, + font-size-3xl: #{var.$font-size_3xl}, + line-height: #{var.$line-height}, + ) +); diff --git a/src/scss/base/_helpers.scss b/src/scss/base/_helpers.scss new file mode 100644 index 0000000..d6a9233 --- /dev/null +++ b/src/scss/base/_helpers.scss @@ -0,0 +1,44 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; + +.hide { + display: none !important; +} + +/* Text meant only for screen readers. */ +.screen-reader-text { + border: 0; + clip: rect(1px, 1px, 1px, 1px); + height: fun.convert-px(1); + overflow: hidden; + padding: 0; + position: absolute !important; + width: fun.convert-px(1); + word-break: normal; + word-wrap: normal !important; /* Many screen reader and browser combinations announce broken words as they would appear visually. */ + + &:focus { + background: fun.get-var(color-bg); + border: fun.convert-px(3) solid fun.get-var(color-border); + box-shadow: 0 0 fun.convert-px(2) fun.convert-px(2) + fun.get-var(color-shadow-light); + clip: auto !important; + color: fun.get-var(color-primary); + display: block; + font-size: fun.get-var(font-size-md); + font-weight: 600; + height: auto; + left: 0; + padding: fun.get-var(spacing-sm) fun.get-var(spacing-md); + top: 0; + width: auto; + z-index: 100000; + } +} + +@include mix.motion("reduce") { + * { + animation: none !important; + transition: none !important; + } +} diff --git a/src/scss/base/_spacings.scss b/src/scss/base/_spacings.scss new file mode 100644 index 0000000..e908caf --- /dev/null +++ b/src/scss/base/_spacings.scss @@ -0,0 +1,24 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; +@use "../abstracts/variables" as var; +@include mix.set-vars( + ( + spacing-3xs: var.$spacing_3xs, + spacing-2xs: var.$spacing_2xs, + spacing-xs: var.$spacing_xs, + spacing-sm: var.$spacing_sm, + spacing-md: var.$spacing_md, + spacing-lg: var.$spacing_lg, + toolbar-height: fun.convert-px(60), + ) +); + +@include mix.media("screen") { + @include mix.dimensions("lg") { + @include mix.set-vars( + ( + toolbar-height: fun.convert-px(0), + ) + ); + } +} diff --git a/src/scss/base/_typography.scss b/src/scss/base/_typography.scss new file mode 100644 index 0000000..b0504b7 --- /dev/null +++ b/src/scss/base/_typography.scss @@ -0,0 +1,48 @@ +@use "../abstracts/functions" as fun; + +*::selection { + background: fun.get-var(color-primary-light-opacity); +} + +body { + background: fun.get-var(color-bg); + color: fun.get-var(color-fg); + font-size: fun.get-var(font-size-md); + line-height: fun.get-var(line-height); +} + +h1, +h2, +h3, +h4, +h5, +h6, +p, +ul { + margin: 0 0 fun.get-var(spacing-sm); +} + +a { + color: fun.get-var(color-primary); + text-decoration-thickness: fun.convert-px(2); + text-underline-offset: fun.convert-px(3); + transition: all 0.3s ease-in-out 0s; + + &:hover, + &:focus { + color: fun.get-var(color-primary-light); + text-decoration-color: fun.get-var(color-primary-light); + text-decoration-thickness: fun.convert-px(4); + } + + &:focus { + outline: fun.get-var(color-primary) dotted fun.convert-px(1); + } + + &:active { + color: fun.get-var(color-primary-dark); + outline: none; + text-decoration-color: fun.get-var(color-primary-dark); + text-decoration-thickness: fun.convert-px(2); + } +} diff --git a/src/scss/components/_buttons.scss b/src/scss/components/_buttons.scss new file mode 100644 index 0000000..bc7959e --- /dev/null +++ b/src/scss/components/_buttons.scss @@ -0,0 +1,21 @@ +@use "../abstracts/functions" as fun; + +.btn { + background: fun.get-var(color-bg); + border: 0; + color: fun.get-var(color-primary); + cursor: pointer; + display: block; + font-weight: 600; + + &:hover, + &:focus { + background: fun.get-var(color-primary); + color: fun.get-var(color-fg-inverted); + } + + &:active { + background: fun.get-var(color-bg); + color: fun.get-var(color-primary); + } +} diff --git a/src/scss/layout/_footer.scss b/src/scss/layout/_footer.scss new file mode 100644 index 0000000..7dce0dc --- /dev/null +++ b/src/scss/layout/_footer.scss @@ -0,0 +1,40 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; + +.footer { + align-items: center; + background: fun.get-var(color-bg-secondary); + border-top: fun.convert-px(1) solid fun.get-var(color-border-light); + display: flex; + flex-flow: row wrap; + font-family: fun.get-var(font-family-secondary); + font-size: fun.get-var(font-size-md); + gap: fun.get-var(spacing-3xs); + justify-content: center; + padding: fun.get-var(spacing-sm) fun.get-var(spacing-md) + calc(#{fun.get-var(toolbar-height)} + #{fun.get-var(spacing-sm)}); + + @include mix.media("screen") { + @include mix.dimensions("lg") { + box-shadow: 0 -1px 2px 0 fun.get-var(color-shadow); + padding: fun.get-var(spacing-sm) fun.get-var(spacing-md); + } + } + + .nav { + display: inline-flex; + gap: fun.get-var(spacing-3xs); + + &::after { + content: "/"; + } + } +} + +.copyright { + align-items: center; + display: flex; + flex-flow: row wrap; + gap: fun.get-var(spacing-3xs); + justify-content: center; +} diff --git a/src/scss/layout/_grid.scss b/src/scss/layout/_grid.scss new file mode 100644 index 0000000..3749678 --- /dev/null +++ b/src/scss/layout/_grid.scss @@ -0,0 +1,43 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; + +.body { + display: grid; + grid-template-columns: minmax(0, 1fr); + grid-template-rows: minmax(0, 1fr) max-content; + height: 100vh; + position: relative; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + grid-template-columns: 1.5fr 4fr; + } + + @include mix.dimensions("xl") { + grid-template-columns: 1fr 4fr; + } + } +} + +.header { + grid-column: 1; + grid-row: 1; + width: 100%; +} + +.main { + grid-column: 1; + grid-row: 1 / -1; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + grid-column: 2; + } + } +} + +.footer { + grid-column: 1; + grid-row: 2; + width: 100%; +} diff --git a/src/scss/layout/_header.scss b/src/scss/layout/_header.scss new file mode 100644 index 0000000..cbc1693 --- /dev/null +++ b/src/scss/layout/_header.scss @@ -0,0 +1,143 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; + +.header { + background: fun.get-var(color-bg-secondary); + overflow-y: auto; + padding: fun.get-var(spacing-md) + clamp(#{fun.get-var(spacing-md)}, 3vw, #{fun.get-var(spacing-lg)}); + scrollbar-color: fun.get-var(color-primary-light-opacity) + fun.get-var(color-bg-tertiary); + z-index: 5; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + box-shadow: 0 -1px 2px 0 fun.get-var(color-shadow); + } + } +} + +.branding { + margin-bottom: clamp( + #{fun.get-var(spacing-sm)}, + 3vw, + #{fun.get-var(spacing-md)} + ); + text-align: center; + + &__title { + font-family: fun.get-var(font-family-secondary); + font-size: clamp( + #{fun.get-var(font-size-2xl)}, + 5vw, + #{fun.get-var(font-size-3xl)} + ); + font-weight: 500; + margin: fun.get-var(spacing-xs) 0 fun.get-var(spacing-3xs); + } + + &__link { + background: linear-gradient( + to top, + fun.get-var(color-primary-light) fun.convert-px(5), + transparent fun.convert-px(5) + ) + center / 0 100% no-repeat; + text-decoration: none; + transition: all 0.5s ease-in-out 0s; + + &:hover, + &:focus { + background-size: 100% 100%; + } + + &:active { + background-size: 0 100%; + } + } + + &__description { + font-family: fun.get-var(font-family-secondary); + font-size: clamp( + #{fun.get-var(font-size-md)}, + 3vw, + #{fun.get-var(font-size-lg)} + ); + font-weight: 400; + letter-spacing: fun.convert-px(1); + margin: 0; + text-transform: uppercase; + } +} + +.logo { + margin: auto; + position: relative; + width: max-content; + + &__image { + backface-visibility: hidden; + border: fun.convert-px(3) solid fun.get-var(color-border-light); + border-radius: 50%; + box-shadow: 0 0 fun.convert-px(6) fun.convert-px(1) + fun.get-var(color-shadow-darker); + left: 0; + position: absolute; + top: 0; + width: 100%; + + &--back { + transform: rotateY(180deg); + } + } + + &__link { + display: block; + height: clamp(#{fun.convert-px(75)}, 15vmin, #{fun.convert-px(90)}); + transform-style: preserve-3d; + transition: all 0.6s linear 0s; + width: clamp(#{fun.convert-px(75)}, 15vmin, #{fun.convert-px(90)}); + + &:hover, + &:focus { + outline: none; + transform: rotateY(180deg); + } + + &:hover &, + &:focus & { + &__image { + &--front { + transform: none; + } + + &--back { + transform: rotateY(180deg); + } + } + } + + &:focus & { + &__image { + box-shadow: 0 0 fun.convert-px(6) fun.convert-px(1) + fun.get-var(color-shadow-dark), + 0 0 0 fun.convert-px(5) fun.get-var(color-primary-light-opacity); + outline: none; + } + } + + &:active & { + &__image { + box-shadow: 0 0 fun.convert-px(6) fun.convert-px(1) + fun.get-var(color-shadow-dark), + 0 0 0 fun.convert-px(7) fun.get-var(color-primary-light-opacity); + } + } + } + + &:hover & { + &__link { + transform: rotateY(180deg); + } + } +} diff --git a/src/scss/layout/_main.scss b/src/scss/layout/_main.scss new file mode 100644 index 0000000..8ab842b --- /dev/null +++ b/src/scss/layout/_main.scss @@ -0,0 +1,138 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; +@use "../abstracts/placeholders"; + +.main { + display: flex; + flex-flow: column nowrap; + height: calc(100% - #{fun.get-var(toolbar-height)}); + + @include mix.media("screen") { + @include mix.dimensions("lg") { + display: grid; + grid-template-columns: 5fr 2fr; + } + + @include mix.dimensions("xl") { + grid-template-columns: 4fr 1fr; + } + } +} + +// NoScript extension seems to replace noscript tag with a span. +.main > span, +.instructions, +noscript { + background: fun.get-var(color-bg); + padding: fun.get-var(spacing-md); + text-align: center; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + grid-column: 1 / -1; + } + } +} + +.instructions { + align-items: center; + display: flex; + justify-content: center; +} + +.legal-notice { + height: 100%; + overflow-y: auto; + padding: clamp(#{fun.get-var(spacing-md)}, 3vw, #{fun.get-var(spacing-lg)}); + scrollbar-color: fun.get-var(color-primary-light-opacity) + fun.get-var(color-bg-tertiary); + width: 100%; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + grid-column: 1 / -1; + } + } +} + +.project-preview { + background: fun.get-var(color-bg); + flex: 0 1 100%; + min-height: 0; + width: 100%; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + height: 100%; + } + } + + iframe { + border: 0; + height: 100%; + width: 100%; + } +} + +.project-details { + background: fun.get-var(color-bg-secondary); + box-shadow: 0 -1px 2px 0 fun.get-var(color-shadow); + flex: 1 0 100%; + overflow-y: auto; + padding: fun.get-var(spacing-md); + scrollbar-color: fun.get-var(color-primary-light-opacity) + fun.get-var(color-bg-tertiary); + + @include mix.media("screen") { + @include mix.dimensions("lg") { + font-size: fun.get-var(font-size-md); + } + } + + &__description { + margin-bottom: fun.get-var(spacing-md); + white-space: pre-wrap; + } + + .list { + &--tech { + padding-left: fun.get-var(spacing-sm); + } + + &--repos { + @extend %flex-list; + + gap: fun.get-var(spacing-xs); + } + + &__link { + background-repeat: no-repeat; + background-size: contain; + box-shadow: 0 0 0 0 fun.get-var(color-shadow); + display: block; + height: fun.convert-px(50); + transition: transform 0.3s ease-in-out 0s, + box-shadow 0.15s ease-in-out 0.15s; + width: fun.convert-px(50); + + &--github { + background: url(#{fun.encode-svg('<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path style="fill:#1b1817;fill-opacity:1;opacity:1;stroke-width:6.55748" d="M0 0h100v100H0z"/><path d="M50.003 15.864C69.33 15.864 85 31.534 85 50.865c0 15.464-10.028 28.581-23.936 33.211-1.75.32-2.389-.76-2.389-1.689 0-.829.03-3.031.047-5.951 9.736 2.114 11.79-4.693 11.79-4.693 1.592-4.044 3.887-5.12 3.887-5.12 3.178-2.17-.241-2.127-.241-2.127-3.513.247-5.36 3.607-5.36 3.607-3.123 5.348-8.193 3.803-10.187 2.907-.318-2.26-1.22-3.803-2.222-4.677 7.772-.883 15.943-3.887 15.943-17.299 0-3.82-1.365-6.944-3.604-9.391.361-.886 1.563-4.444-.341-9.263 0 0-2.94-.941-9.626 3.588-2.791-.778-5.786-1.164-8.762-1.177-2.972.013-5.967.4-8.762 1.177-6.682-4.53-9.615-3.588-9.615-3.588-1.91 4.82-.71 8.377-.348 9.263-2.243 2.447-3.6 5.571-3.6 9.391 0 13.446 8.185 16.405 15.982 17.271-1.257 1.08-2.376 3.216-2.376 6.482 0 4.678.043 8.453.043 9.6 0 .937-.63 2.027-2.407 1.685C25.02 79.433 15 66.324 15 50.865c0-19.331 15.672-35.001 35.003-35.001" style="fill:#fff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:.999999"/></svg>')}); + } + + &--gitlab { + background: url(#{fun.encode-svg('<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path style="opacity:1;fill:#ccc;fill-opacity:1;stroke-width:7.26231" d="M0 0h100v100H0z"/><path class="st3" d="m49.998 82.237 12.895-39.668H37.121Z" style="fill:#e24329;stroke-width:1"/><path class="st4" d="M19.058 42.57 15.13 54.62a2.67 2.67 0 0 0 .966 2.984l33.9 24.632Z" style="fill:#fca326;stroke-width:1"/><path class="st3" d="M19.058 42.57H37.12l-7.774-23.89c-.398-1.222-2.132-1.222-2.544 0z" style="fill:#e24329;stroke-width:1"/><path class="st4" d="m80.956 42.57 3.914 12.05a2.67 2.67 0 0 1-.966 2.984L49.998 82.237Z" style="fill:#fca326;stroke-width:1"/><path class="st3" d="M80.956 42.57H62.894l7.759-23.89c.398-1.222 2.132-1.222 2.544 0z" style="fill:#e24329;stroke-width:1"/><path style="fill:#fc6d26;stroke-width:4.82321" class="st5" d="m50.017 82.237 30.94-39.667H62.893Zm-.019 0L19.058 42.57H37.12z"/></svg>')}); + } + + &:hover, + &:focus { + box-shadow: fun.convert-px(-1) fun.convert-px(1) fun.convert-px(4) + fun.convert-px(2) fun.get-var(color-shadow-light); + transform: scale(1.15); + } + + &:active { + opacity: 1; + } + } + } +} diff --git a/src/scss/layout/_nav.scss b/src/scss/layout/_nav.scss new file mode 100644 index 0000000..98e4cb5 --- /dev/null +++ b/src/scss/layout/_nav.scss @@ -0,0 +1,70 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/placeholders"; + +.nav { + text-align: center; + + &__label { + font-weight: 600; + } + + &__list { + @extend %reset-list; + + .btn { + width: 100%; + } + } + + &:not(&--footer) &__item { + margin: fun.get-var(spacing-2xs) 0; + } + + &:not(&--footer) &__link { + background-image: linear-gradient( + to left, + #{fun.get-var(color-bg)} 0, + #{fun.get-var(color-bg)} 50%, + #{fun.get-var(color-primary)} 50% + ); + background-position: 100% 0; + background-size: 200% 100%; + border: fun.convert-px(3) solid fun.get-var(color-border); + border-radius: fun.convert-px(50); + display: block; + font-weight: 600; + margin: auto; + padding: fun.get-var(spacing-3xs); + position: relative; + text-decoration: none; + transition: all 0.4s ease-in-out 0s; + width: 75%; + + &:hover, + &:focus { + background-position: 0 0; + color: fun.get-var(color-fg-inverted); + } + + &:active { + background-position: 100% 0; + color: fun.get-var(color-primary-dark); + text-decoration: fun.convert-px(1) solid underline; + } + + &--selected { + background: fun.get-var(color-primary-dark); + box-shadow: inset 0 0 0 4px fun.get-var(color-bg); + color: fun.get-var(color-fg-inverted); + + &:hover, + &:focus { + background: fun.get-var(color-primary-light); + } + } + } + + .btn { + margin: auto; + } +} diff --git a/src/scss/layout/_toolbar.scss b/src/scss/layout/_toolbar.scss new file mode 100644 index 0000000..00e2bd7 --- /dev/null +++ b/src/scss/layout/_toolbar.scss @@ -0,0 +1,34 @@ +@use "../abstracts/functions" as fun; + +.toolbar { + align-items: center; + background: fun.get-var(color-primary); + bottom: 0; + box-shadow: 0 -1px 2px 0 fun.get-var(color-shadow-dark); + color: fun.get-var(color-fg-inverted); + display: flex; + flex-flow: row nowrap; + gap: fun.get-var(spacing-xs); + height: fun.get-var(toolbar-height); + justify-content: center; + left: 0; + padding: 0 fun.get-var(spacing-sm); + position: absolute; + right: 0; + z-index: 2; + + & > &__options { + background: fun.get-var(color-primary); + color: fun.get-var(color-fg-inverted); + font-size: fun.get-var(font-size-sm); + height: 85%; + line-height: inherit; + padding: 0 fun.get-var(spacing-xs); + + &:hover, + &:focus { + background: fun.get-var(color-bg); + color: fun.get-var(color-primary); + } + } +} diff --git a/src/scss/style.scss b/src/scss/style.scss new file mode 100644 index 0000000..96c8fe5 --- /dev/null +++ b/src/scss/style.scss @@ -0,0 +1,40 @@ +@charset 'utf-8'; + +/** + * 1.0 Vendors + * + * Import each files separately to define vendors styles order. + */ +@use "modern-normalize"; + +/** + * 2.0 Base + * + * Define some standard styles and CSS variables (colors, fonts...). + */ +@use "base/base"; +@use "base/animations"; +@use "base/colors"; +@use "base/fonts"; +@use "base/helpers"; +@use "base/spacings"; +@use "base/typography"; + +/** + * 3.0 Layout + * + * Define website layout. + */ +@use "layout/grid"; +@use "layout/header"; +@use "layout/main"; +@use "layout/footer"; +@use "layout/toolbar"; +@use "layout/nav"; + +/** +* 4.0 Components +* +* Define styles for all kind of specific modules like buttons, widgets... +*/ +@use "components/buttons"; |
