From ccf76a56168477f30e63fe959c45c621fb82f31d Mon Sep 17 00:00:00 2001 From: Oleh Omelchenko Date: Sat, 10 Jan 2026 05:15:42 +0200 Subject: [PATCH] feat: custom theme --- _includes/fonts.html | 3 + _quarto.yml | 6 +- about/index.qmd | 6 +- custom-theme.scss | 14 ++ scss/_colors.scss | 44 ++++++ scss/_components.scss | 100 ++++++++++++++ scss/_dataviz.scss | 53 +++++++ scss/_layout.scss | 2 + scss/_typography.scss | 31 +++++ scss/_utilities.scss | 36 +++++ scss/_variables.scss | 33 +++++ styles.css | 20 +-- themes-guide.md | 313 ++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 644 insertions(+), 17 deletions(-) create mode 100644 _includes/fonts.html create mode 100644 custom-theme.scss create mode 100644 scss/_colors.scss create mode 100644 scss/_components.scss create mode 100644 scss/_dataviz.scss create mode 100644 scss/_layout.scss create mode 100644 scss/_typography.scss create mode 100644 scss/_utilities.scss create mode 100644 scss/_variables.scss create mode 100644 themes-guide.md diff --git a/_includes/fonts.html b/_includes/fonts.html new file mode 100644 index 0000000..92a254d --- /dev/null +++ b/_includes/fonts.html @@ -0,0 +1,3 @@ + + + diff --git a/_quarto.yml b/_quarto.yml index 5d262fd..a0ca229 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -49,11 +49,13 @@ website: format: html: - theme: cosmo + theme: custom-theme.scss css: styles.css toc: false page-layout: article - include-in-header: _includes/analytics.html + include-in-header: + - _includes/analytics.html + - _includes/fonts.html execute: freeze: auto diff --git a/about/index.qmd b/about/index.qmd index fd62e41..b3d02f7 100644 --- a/about/index.qmd +++ b/about/index.qmd @@ -1,15 +1,13 @@ --- -title: "About" +title: "About Oleh Omelchenko" page-layout: article --- -## Hi, I'm Oleh Omelchenko ### Background -Add your background, education, and experience here. ### Skills & Expertise @@ -42,7 +40,5 @@ Check out my [portfolio](/portfolio/) and [projects](/projects/) pages to see ex ### Contact - GitHub: [github.com/olehomelchenko](https://github.com/olehomelchenko) -- Email: [your-email@example.com](mailto:your-email@example.com) - LinkedIn: [olehomelchenko](https://linkedin.com/in/olehomelchenko) ---- diff --git a/custom-theme.scss b/custom-theme.scss new file mode 100644 index 0000000..58bbaac --- /dev/null +++ b/custom-theme.scss @@ -0,0 +1,14 @@ +/*-- scss:defaults --*/ + +// Import variables FIRST (must come before Bootstrap) +@import "scss/variables"; + +/*-- scss:rules --*/ + +// Import our custom modules +@import "scss/colors"; +@import "scss/typography"; +@import "scss/utilities"; +@import "scss/components"; +@import "scss/dataviz"; +@import "scss/layout"; diff --git a/scss/_colors.scss b/scss/_colors.scss new file mode 100644 index 0000000..441f4ae --- /dev/null +++ b/scss/_colors.scss @@ -0,0 +1,44 @@ +:root { + // Brand Colors + --color-primary-blue: #{$primary-blue}; + --color-primary-yellow: #{$primary-yellow}; + --color-text: #{$text-color}; + --color-background: #{$background-color}; + + // Semantic colors + --text: #2c2a26; + --background: #f5f3f0; + --primary: #296eb3; + --secondary: #fdba35; + --accent: #188afb; + + // UI Elements + --link-color: #{$primary-blue}; + --link-hover-color: #{darken($primary-blue, 10%)}; + + // Data Visualization Colors + --dataviz-cat-1: #{$dataviz-cat-1}; + --dataviz-cat-2: #{$dataviz-cat-2}; + --dataviz-cat-3: #{$dataviz-cat-3}; + --dataviz-cat-4: #{$dataviz-cat-4}; + --dataviz-cat-5: #{$dataviz-cat-5}; + --dataviz-cat-6: #{$dataviz-cat-6}; + --dataviz-cat-7: #{$dataviz-cat-7}; + --dataviz-cat-8: #{$dataviz-cat-8}; +} + +// Apply colors +body { + background-color: var(--color-background); + color: var(--color-text); +} + +a { + color: var(--link-color); + text-decoration: none; + + &:hover { + color: var(--link-hover-color); + text-decoration: underline; + } +} diff --git a/scss/_components.scss b/scss/_components.scss new file mode 100644 index 0000000..71fc222 --- /dev/null +++ b/scss/_components.scss @@ -0,0 +1,100 @@ +// Navbar styling +.navbar { + background-color: var(--color-background) !important; + border-bottom: 2px solid var(--color-text); + + .navbar-brand { + color: var(--color-text) !important; + font-family: $headings-font-family; + font-weight: 600; + } + + .navbar-nav .nav-link { + color: var(--color-text) !important; + + &:hover { + color: var(--color-primary-blue) !important; + } + + &.active { + color: var(--color-primary-blue) !important; + } + } +} + +// Footer +.nav-footer { + background-color: var(--color-background); + border-top: 2px solid var(--color-text); + color: var(--color-text); + + a { + color: var(--color-primary-blue); + } +} + +// Buttons +.btn-primary { + background-color: var(--color-primary-blue); + border-color: var(--color-primary-blue); + color: white; + + &:hover { + background-color: #{darken($primary-blue, 10%)}; + border-color: #{darken($primary-blue, 10%)}; + } +} + +.btn-secondary { + background-color: var(--color-primary-yellow); + border-color: var(--color-primary-yellow); + color: var(--color-text); + + &:hover { + background-color: #{darken($primary-yellow, 10%)}; + border-color: #{darken($primary-yellow, 10%)}; + } +} + +// Code blocks +pre.sourceCode { + background-color: rgba(45, 42, 38, 0.05); + border: 1px solid rgba(45, 42, 38, 0.1); + padding: 1em; +} + +code.sourceCode { + color: var(--color-text); +} + +// Quarto title block +.quarto-title-block { + border-bottom: 2px solid var(--color-text); + margin-bottom: 2rem; + + .quarto-title .title { + font-family: $headings-font-family; + color: var(--color-text); + } +} + +// Listing pages +.quarto-listing-default { + .listing-item { + border: 1px solid rgba(45, 42, 38, 0.2); + padding: 1rem; + margin-bottom: 1rem; + + &:hover { + border-color: var(--color-primary-blue); + } + } + + .listing-title a { + color: var(--color-text); + + &:hover { + color: var(--color-primary-blue); + } + } +} diff --git a/scss/_dataviz.scss b/scss/_dataviz.scss new file mode 100644 index 0000000..030b628 --- /dev/null +++ b/scss/_dataviz.scss @@ -0,0 +1,53 @@ +// Sequential color ramps +// Blue sequential (5 steps from light to dark) +:root { + --dataviz-blue-seq-1: #e6f2ff; + --dataviz-blue-seq-2: #9bccfd; + --dataviz-blue-seq-3: #3699fc; + --dataviz-blue-seq-4: #047ffb; + --dataviz-blue-seq-5: #024c97; + + // Yellow sequential (5 steps) + --dataviz-yellow-seq-1: #fff6e6; + --dataviz-yellow-seq-2: #fedd9a; + --dataviz-yellow-seq-3: #fdba35; + --dataviz-yellow-seq-4: #ca8702; + --dataviz-yellow-seq-5: #654401; + + // Diverging scale (blue ↔ neutral ↔ yellow) + --dataviz-diverging-1: #296EB4; + --dataviz-diverging-2: #9FDFDC; + --dataviz-diverging-3: #f5f3f0; + --dataviz-diverging-4: #FDB833; + --dataviz-diverging-5: #fca903; +} + +// Categorical color utility classes (for future use) +.dataviz-cat-1 { color: $dataviz-cat-1; } +.dataviz-cat-2 { color: $dataviz-cat-2; } +.dataviz-cat-3 { color: $dataviz-cat-3; } +.dataviz-cat-4 { color: $dataviz-cat-4; } +.dataviz-cat-5 { color: $dataviz-cat-5; } +.dataviz-cat-6 { color: $dataviz-cat-6; } +.dataviz-cat-7 { color: $dataviz-cat-7; } +.dataviz-cat-8 { color: $dataviz-cat-8; } + +.dataviz-cat-bg-1 { background-color: $dataviz-cat-1; } +.dataviz-cat-bg-2 { background-color: $dataviz-cat-2; } +.dataviz-cat-bg-3 { background-color: $dataviz-cat-3; } +.dataviz-cat-bg-4 { background-color: $dataviz-cat-4; } +.dataviz-cat-bg-5 { background-color: $dataviz-cat-5; } +.dataviz-cat-bg-6 { background-color: $dataviz-cat-6; } +.dataviz-cat-bg-7 { background-color: $dataviz-cat-7; } +.dataviz-cat-bg-8 { background-color: $dataviz-cat-8; } + +/* + * Data Visualization Color System + * + * Categorical (8 colors): Use .dataviz-cat-1 through .dataviz-cat-8 + * Sequential Blue: var(--dataviz-blue-seq-1) through var(--dataviz-blue-seq-5) + * Sequential Yellow: var(--dataviz-yellow-seq-1) through var(--dataviz-yellow-seq-5) + * Diverging: var(--dataviz-diverging-1) through var(--dataviz-diverging-5) + * + * All colors are colorblind-safe as per brand guidelines. + */ diff --git a/scss/_layout.scss b/scss/_layout.scss new file mode 100644 index 0000000..dc520d3 --- /dev/null +++ b/scss/_layout.scss @@ -0,0 +1,2 @@ +// Layout-specific styles +// Initially empty - for future layout customizations diff --git a/scss/_typography.scss b/scss/_typography.scss new file mode 100644 index 0000000..2b3a7ca --- /dev/null +++ b/scss/_typography.scss @@ -0,0 +1,31 @@ +// Body text +body { + font-family: $font-family-sans-serif; + font-optical-sizing: auto; +} + +// Headings +h1, h2, h3, h4, h5, h6, +.h1, .h2, .h3, .h4, .h5, .h6 { + font-family: $headings-font-family; + font-optical-sizing: auto; + color: var(--color-text); +} + +// Code blocks +code, pre, kbd, samp { + font-family: $font-family-monospace; +} + +// Quarto-specific code blocks +.sourceCode { + font-family: $font-family-monospace; +} + +// Inline code +p code, li code { + font-family: $font-family-monospace; + background-color: rgba(45, 42, 38, 0.05); + padding: 0.2em 0.4em; + color: var(--color-text); +} diff --git a/scss/_utilities.scss b/scss/_utilities.scss new file mode 100644 index 0000000..f0909b1 --- /dev/null +++ b/scss/_utilities.scss @@ -0,0 +1,36 @@ +// Global border-radius override (sharp corners principle) +* { + border-radius: 0 !important; +} + +// Remove any gradients from buttons +.btn { + background-image: none !important; + border-radius: 0 !important; +} + +// Navbar - sharp corners, solid colors +.navbar { + border-radius: 0 !important; + background-image: none !important; +} + +// Cards and panels +.card { + border-radius: 0 !important; +} + +// Code blocks +pre, code { + border-radius: 0 !important; +} + +// Quarto-specific elements +.quarto-title-block { + border-radius: 0 !important; +} + +// Input elements +input, select, textarea, button { + border-radius: 0 !important; +} diff --git a/scss/_variables.scss b/scss/_variables.scss new file mode 100644 index 0000000..f5160ef --- /dev/null +++ b/scss/_variables.scss @@ -0,0 +1,33 @@ +// Brand Colors +$primary-blue: #1789fc; +$primary-yellow: #fdb833; +$text-color: #2d2a26; +$background-color: #f5f3f0; + +// Bootstrap/Quarto Variable Overrides +$primary: $primary-blue; +$secondary: $primary-yellow; +$body-bg: $background-color; +$body-color: $text-color; + +// Typography +$font-family-sans-serif: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; +$font-family-monospace: "IBM Plex Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; +$headings-font-family: "Finlandica", "IBM Plex Sans", sans-serif; + +// Design Principles +$border-radius: 0; +$border-radius-sm: 0; +$border-radius-lg: 0; +$enable-rounded: false; +$enable-gradients: false; + +// Data Viz Categorical Colors +$dataviz-cat-1: #296EB4; +$dataviz-cat-2: #FDB833; +$dataviz-cat-3: #CCE160; +$dataviz-cat-4: #9FDFDC; +$dataviz-cat-5: #8A983E; +$dataviz-cat-6: #C7C7FA; +$dataviz-cat-7: #D02F2F; +$dataviz-cat-8: #A62191; diff --git a/styles.css b/styles.css index 791fa6d..2c3e1d6 100644 --- a/styles.css +++ b/styles.css @@ -31,9 +31,9 @@ } .vega-bindings:not(:empty) { - background: #f8f9fa; - border: 1px solid #dee2e6; - border-radius: 8px; + background: var(--color-background, #f5f3f0); + border: 1px solid rgba(45, 42, 38, 0.2); + border-radius: 0; padding: 15px 20px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); width: fit-content; @@ -44,28 +44,28 @@ align-items: center; gap: 10px; margin-right: 20px; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 14px; - color: #495057; + color: var(--color-text, #2d2a26); font-weight: 500; } .vega-bindings input, .vega-bindings select { padding: 6px 12px; - border: 1px solid #ced4da; - border-radius: 4px; + border: 1px solid rgba(45, 42, 38, 0.2); + border-radius: 0; background: white; font-size: 14px; - color: #495057; + color: var(--color-text, #2d2a26); transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } .vega-bindings input:focus, .vega-bindings select:focus { - border-color: #80bdff; + border-color: var(--color-primary-blue, #1789fc); outline: 0; - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + box-shadow: 0 0 0 0.2rem rgba(23, 137, 252, 0.25); } .vega-bindings select { diff --git a/themes-guide.md b/themes-guide.md new file mode 100644 index 0000000..4a1eacb --- /dev/null +++ b/themes-guide.md @@ -0,0 +1,313 @@ + +## Personal Design System + +### Brand Colors + +| Role | Hex | Usage | +|------|-----|-------| +| Primary Blue | `#1789fc` | UI accents, links, interactive elements | +| Primary Yellow | `#fdb833` | Highlights, secondary accents | +| Text | `#2d2a26` | Body text, headings | +| Background | `#f5f3f0` | Page background | + +### Data Visualization + +**Categorical (8 colors):** +`#296EB4` `#FDB833` `#CCE160` `#9FDFDC` `#8A983E` `#C7C7FA` `#D02F2F` `#A62191` + +**Sequential:** Ramps derived from `#1789fc` (blue) or `#fdb833` (yellow) + +**Diverging:** Blue ↔ neutral midpoint ↔ Yellow + +### Typography + +| Role | Font | +|------|------| +| Headings | Finlandica | +| Body | IBM Plex Sans | +| Code | IBM Plex Mono | + +### Design Principles + +- Sharp corners, no border-radius +- Solid fills over gradients +- Light mode only +- Colorblind-safe palette + + +## Font instructions from Google Fonts +Code below was generated by Google Fonts: + + +``` + +Embed code in the of your html + + + + + + + +IBM Plex Sans: CSS class for a variable style + + +.ibm-plex-sans- { + font-family: "IBM Plex Sans", sans-serif; + font-optical-sizing: auto; + font-weight: ; + font-style: normal; + font-variation-settings: + "wdth" 100; +} + + +Finlandica: CSS class for a variable style + + +.finlandica- { + font-family: "Finlandica", sans-serif; + font-optical-sizing: auto; + font-weight: ; + font-style: normal; +} + +IBM Plex Mono: CSS classes + +.ibm-plex-mono-thin { + font-family: "IBM Plex Mono", monospace; + font-weight: 100; + font-style: normal; +} + +.ibm-plex-mono-extralight { + font-family: "IBM Plex Mono", monospace; + font-weight: 200; + font-style: normal; +} + +.ibm-plex-mono-light { + font-family: "IBM Plex Mono", monospace; + font-weight: 300; + font-style: normal; +} + +.ibm-plex-mono-regular { + font-family: "IBM Plex Mono", monospace; + font-weight: 400; + font-style: normal; +} + +.ibm-plex-mono-medium { + font-family: "IBM Plex Mono", monospace; + font-weight: 500; + font-style: normal; +} + +.ibm-plex-mono-semibold { + font-family: "IBM Plex Mono", monospace; + font-weight: 600; + font-style: normal; +} + +.ibm-plex-mono-bold { + font-family: "IBM Plex Mono", monospace; + font-weight: 700; + font-style: normal; +} + +.ibm-plex-mono-thin-italic { + font-family: "IBM Plex Mono", monospace; + font-weight: 100; + font-style: italic; +} + +.ibm-plex-mono-extralight-italic { + font-family: "IBM Plex Mono", monospace; + font-weight: 200; + font-style: italic; +} + +.ibm-plex-mono-light-italic { + font-family: "IBM Plex Mono", monospace; + font-weight: 300; + font-style: italic; +} + +.ibm-plex-mono-regular-italic { + font-family: "IBM Plex Mono", monospace; + font-weight: 400; + font-style: italic; +} + +.ibm-plex-mono-medium-italic { + font-family: "IBM Plex Mono", monospace; + font-weight: 500; + font-style: italic; +} + +.ibm-plex-mono-semibold-italic { + font-family: "IBM Plex Mono", monospace; + font-weight: 600; + font-style: italic; +} + +.ibm-plex-mono-bold-italic { + font-family: "IBM Plex Mono", monospace; + font-weight: 700; + font-style: italic; +} + +``` + + +## Colors for website theme + +The code below was generated by Realtime Colors website. + +General variables: + +``` +:root[data-theme="light"] { + --text: #2c2a26; + --background: #f5f3f0; + --primary: #296eb3; + --secondary: #fdba35; + --accent: #188afb; +} +:root[data-theme="dark"] { + --text: #d9d7d3; + --background: #0f0d0a; + --primary: #4c91d6; + --secondary: #ca8702; + --accent: #0475e7; +} +``` + +Option with shades: +``` +:root[data-theme="light"] { + --text-50: #f3f3f1; + --text-100: #e7e6e4; + --text-200: #d0cdc8; + --text-300: #b8b4ad; + --text-400: #a09b92; + --text-500: #888277; + --text-600: #6d685f; + --text-700: #524e47; + --text-800: #37342f; + --text-900: #1b1a18; + --text-950: #0e0d0c; + + --background-50: #f5f3f0; + --background-100: #ebe7e0; + --background-200: #d6cec2; + --background-300: #c2b6a3; + --background-400: #ad9d85; + --background-500: #998566; + --background-600: #7a6a52; + --background-700: #5c503d; + --background-800: #3d3529; + --background-900: #1f1b14; + --background-950: #0f0d0a; + + --primary-50: #eaf2fa; + --primary-100: #d5e5f6; + --primary-200: #acccec; + --primary-300: #82b2e3; + --primary-400: #5999d9; + --primary-500: #2f7fd0; + --primary-600: #2666a6; + --primary-700: #1c4c7d; + --primary-800: #133353; + --primary-900: #09192a; + --primary-950: #050d15; + + --secondary-50: #fff6e6; + --secondary-100: #feeecd; + --secondary-200: #fedd9a; + --secondary-300: #fdcb68; + --secondary-400: #fdba35; + --secondary-500: #fca903; + --secondary-600: #ca8702; + --secondary-700: #976502; + --secondary-800: #654401; + --secondary-900: #322201; + --secondary-950: #191100; + + --accent-50: #e6f2ff; + --accent-100: #cde5fe; + --accent-200: #9bccfd; + --accent-300: #68b2fd; + --accent-400: #3699fc; + --accent-500: #047ffb; + --accent-600: #0366c9; + --accent-700: #024c97; + --accent-800: #023364; + --accent-900: #011932; + --accent-950: #000d19; + +} +:root[data-theme="dark"] { + --text-50: #0e0d0c; + --text-100: #1b1a18; + --text-200: #37342f; + --text-300: #524e47; + --text-400: #6d685f; + --text-500: #888277; + --text-600: #a09b92; + --text-700: #b8b4ad; + --text-800: #d0cdc8; + --text-900: #e7e6e4; + --text-950: #f3f3f1; + + --background-50: #0f0d0a; + --background-100: #1f1b14; + --background-200: #3d3529; + --background-300: #5c503d; + --background-400: #7a6a52; + --background-500: #998566; + --background-600: #ad9d85; + --background-700: #c2b6a3; + --background-800: #d6cec2; + --background-900: #ebe7e0; + --background-950: #f5f3f0; + + --primary-50: #050d15; + --primary-100: #09192a; + --primary-200: #133353; + --primary-300: #1c4c7d; + --primary-400: #2666a6; + --primary-500: #2f7fd0; + --primary-600: #5999d9; + --primary-700: #82b2e3; + --primary-800: #acccec; + --primary-900: #d5e5f6; + --primary-950: #eaf2fa; + + --secondary-50: #191100; + --secondary-100: #322201; + --secondary-200: #654401; + --secondary-300: #976502; + --secondary-400: #ca8702; + --secondary-500: #fca903; + --secondary-600: #fdba35; + --secondary-700: #fdcb68; + --secondary-800: #fedd9a; + --secondary-900: #feeecd; + --secondary-950: #fff6e6; + + --accent-50: #000d19; + --accent-100: #011932; + --accent-200: #023364; + --accent-300: #024c97; + --accent-400: #0366c9; + --accent-500: #047ffb; + --accent-600: #3699fc; + --accent-700: #68b2fd; + --accent-800: #9bccfd; + --accent-900: #cde5fe; + --accent-950: #e6f2ff; + +} +``` \ No newline at end of file