diff --git a/.github/workflows/raspberry-mint-dev.yml b/.github/workflows/raspberry-mint-dev.yml new file mode 100644 index 000000000..b848a826e --- /dev/null +++ b/.github/workflows/raspberry-mint-dev.yml @@ -0,0 +1,57 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + pull_request: + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: ./package.json + + - name: npm install + working-directory: ./raspberry-mint-dev + run: npm install + + - name: webpack + working-directory: ./raspberry-mint-dev + run: npm run build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: './raspberry-mint-dev/build' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.stylelintignore b/.stylelintignore index f01501f4d..05d972fe0 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -1 +1,2 @@ prebuild/**/* +/raspberry-mint-dev/build diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml index ff5dd33a8..8b2aca128 100644 --- a/.stylelintrc.yaml +++ b/.stylelintrc.yaml @@ -3,7 +3,8 @@ extends: - stylelint-config-standard-scss plugins: - stylelint-no-unsupported-browser-features - - stylelint-scss rules: import-notation: string no-descending-specificity: ~ + scss/at-extend-no-missing-placeholder: null + scss/no-global-function-names: null diff --git a/bin/fix b/bin/fix index 9d9f4f9eb..1476bfd8d 100755 --- a/bin/fix +++ b/bin/fix @@ -9,7 +9,7 @@ ruff check --fix . ruff format . # Fix CSS code style violations. -./node_modules/.bin/stylelint --fix "./betty/**/*.css" "./betty/**/*.scss" +./node_modules/.bin/stylelint --fix "./betty/**/*.css" "./betty/**/*.scss" "./raspberry-mint-dev/**/*.css" "./raspberry-mint-dev/**/*.scss" # Fix JS code style violations. -./node_modules/.bin/eslint --fix -c ./eslint.config.js ./betty ./playwright +./node_modules/.bin/eslint --fix -c ./eslint.config.js ./betty ./playwright ./raspberry-mint-dev diff --git a/bin/test-eslint b/bin/test-eslint index 084b4f876..28caf5518 100755 --- a/bin/test-eslint +++ b/bin/test-eslint @@ -6,4 +6,4 @@ cd "$(dirname "$0")/.." echo 'Running ESLint...' -./node_modules/.bin/eslint -c ./eslint.config.js ./betty ./playwright "$@" +./node_modules/.bin/eslint -c ./eslint.config.js ./betty ./playwright ./raspberry-mint-dev "$@" diff --git a/bin/test-stylelint b/bin/test-stylelint index 79ccbb930..4e322d402 100755 --- a/bin/test-stylelint +++ b/bin/test-stylelint @@ -6,4 +6,4 @@ cd "$(dirname "$0")/.." echo 'Running Stylelint...' -./node_modules/.bin/stylelint "./betty/**/*.css" "./betty/**/*.scss" +./node_modules/.bin/stylelint "./betty/**/*.css" "./betty/**/*.scss" "./raspberry-mint-dev/**/*.css" "./raspberry-mint-dev/**/*.scss" diff --git a/eslint.config.js b/eslint.config.js index d46a7d5d4..1bed11144 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -11,6 +11,12 @@ const typescriptFiles = [ ] export default [ + { + ignores: [ + "raspberry-mint-dev/build", + ], + }, + // Webpack configuration files. { files: [ diff --git a/raspberry-mint-dev/.gitignore b/raspberry-mint-dev/.gitignore new file mode 100644 index 000000000..8987626e9 --- /dev/null +++ b/raspberry-mint-dev/.gitignore @@ -0,0 +1,5 @@ +/build +/cache +/node_modules +/package-lock.json + diff --git a/raspberry-mint-dev/package.json b/raspberry-mint-dev/package.json new file mode 100644 index 000000000..848cd6a40 --- /dev/null +++ b/raspberry-mint-dev/package.json @@ -0,0 +1,37 @@ +{ + "engines": { + "node": ">= 20" + }, + "dependencies": { + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", + "@babel/preset-typescript": "^7.26.0", + "@popperjs/core": "^2.11.8", + "babel-loader": "^9.2.1", + "bootstrap": "^5.3.3", + "clean-webpack-plugin": "^4.0.0", + "copy-webpack-plugin": "^12.0.2", + "core-js": "^3.38.1", + "css-loader": "^7.1.2", + "css-minimizer-webpack-plugin": "^7.0.0", + "file-loader": "^6.2.0", + "ionicons": "^7.4.0", + "mini-css-extract-plugin": "^2.9.1", + "postcss-loader": "^8.1.1", + "resolve-url-loader": "^5.0.0", + "sass": "^1.80.4", + "sass-loader": "^16.0.2", + "style-loader": "^4.0.0", + "terser-webpack-plugin": "^5.3.10", + "typescript": "^5.6.3", + "webpack": "^5.95.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.1.0", + "html-webpack-plugin": "^5.6.3" + }, + "scripts": { + "build": "webpack --mode development", + "serve": "webpack serve --mode development --open --watch" + }, + "type": "module" +} diff --git a/raspberry-mint-dev/src/css/components/accordion.scss b/raspberry-mint-dev/src/css/components/accordion.scss new file mode 100644 index 000000000..41b5199ca --- /dev/null +++ b/raspberry-mint-dev/src/css/components/accordion.scss @@ -0,0 +1,20 @@ +.accordion-button { + @extend .h6; + + margin-bottom: 0; + + &:focus { + background-color: $focus; + box-shadow: 0 0 $focus, 0 2px $black; + color: $black !important; + text-decoration-color: $black; + } +} + +.accordion-body { + @extend .mb-3; + + // @todo This does not support RTL scripts. + border-right: $border-width solid $black; + margin-right: calc((1.5em - $border-width) / 2); +} diff --git a/raspberry-mint-dev/src/css/components/button.scss b/raspberry-mint-dev/src/css/components/button.scss new file mode 100644 index 000000000..4407227f5 --- /dev/null +++ b/raspberry-mint-dev/src/css/components/button.scss @@ -0,0 +1,32 @@ +.btn { + &:focus { + background-color: $focus; + border-color: $black; + color: $black; + } +} + +@mixin button { + --bs-btn-active-bg: #{$primary-800}; + --bs-btn-active-border-color: #{$primary-800}; + --bs-btn-active-color: #{$white}; + --bs-btn-hover-bg: #{$primary-700}; + --bs-btn-hover-border-color: #{$primary-700}; + --bs-btn-hover-color: #{$white}; +} + +.btn.btn-primary { + @include button; + + --bs-btn-bg: #{$primary}; + --bs-btn-border-color: #{$primary}; + --bs-btn-color: #{$white}; +} + +.btn.btn-secondary { + @include button; + + --bs-btn-bg: #{$white}; + --bs-btn-border-color: #{$primary}; + --bs-btn-color: #{$primary}; +} \ No newline at end of file diff --git a/raspberry-mint-dev/src/css/components/card.scss b/raspberry-mint-dev/src/css/components/card.scss new file mode 100644 index 000000000..50ef9ecd0 --- /dev/null +++ b/raspberry-mint-dev/src/css/components/card.scss @@ -0,0 +1,4 @@ +.card { + border: none; + box-shadow: $border-width $border-width $gray-300; +} diff --git a/raspberry-mint-dev/src/css/components/close.scss b/raspberry-mint-dev/src/css/components/close.scss new file mode 100644 index 000000000..5e7be6b30 --- /dev/null +++ b/raspberry-mint-dev/src/css/components/close.scss @@ -0,0 +1,9 @@ +.btn-close { + border: 3px solid $white; + + &:focus { + background-color: $focus; + border-color: $black; + color: $black; + } +} diff --git a/raspberry-mint-dev/src/css/components/form-check.scss b/raspberry-mint-dev/src/css/components/form-check.scss new file mode 100644 index 000000000..93aeaf7b2 --- /dev/null +++ b/raspberry-mint-dev/src/css/components/form-check.scss @@ -0,0 +1,17 @@ +.form-check { + &:focus-within { + .form-check-label { + background-color: $focus; + box-shadow: 0 0 $focus, 0 2px $black; + color: $black; + text-decoration-color: $black; + outline: none; + + } + + .form-check-input { + border-color: $black; + background-color: $focus; + } + } +} \ No newline at end of file diff --git a/raspberry-mint-dev/src/css/components/form-control-text.scss b/raspberry-mint-dev/src/css/components/form-control-text.scss new file mode 100644 index 000000000..d23adb67e --- /dev/null +++ b/raspberry-mint-dev/src/css/components/form-control-text.scss @@ -0,0 +1,17 @@ +.form-control-text { + &:focus-within { + .form-label { + background-color: $focus; + box-shadow: 0 0 $focus, 0 2px $black; + color: $black; + text-decoration-color: $black; + outline: none; + + } + + .form-control { + border-color: $black; + background-color: $focus; + } + } +} \ No newline at end of file diff --git a/raspberry-mint-dev/src/css/components/form.scss b/raspberry-mint-dev/src/css/components/form.scss new file mode 100644 index 000000000..9a57b8dfd --- /dev/null +++ b/raspberry-mint-dev/src/css/components/form.scss @@ -0,0 +1,4 @@ +// Use `fieldset legend` to be more specific than Bootstrap's own `legend`. +fieldset legend { + @extend .h6; +} diff --git a/raspberry-mint-dev/src/css/components/header.scss b/raspberry-mint-dev/src/css/components/header.scss new file mode 100644 index 000000000..7e5d5b321 --- /dev/null +++ b/raspberry-mint-dev/src/css/components/header.scss @@ -0,0 +1,70 @@ +.site-logo { + @include font-size($h5-font-size); + + color: black; + box-shadow: none; + display: inline-block; + padding-right: 1rem; + + img { + height: 1.5em; + vertical-align: top; + } +} + +.header-entry-point { + @include button; + @include font-size($h5-font-size); + + --bs-btn-bg: #{$white}; + --bs-btn-border-color: #{$white}; + + height: 1lh; + text-indent: -999rem; + width: 1lh; + + &:hover { + --bs-btn-hover-bg: #{$primary-700}; + --bs-btn-hover-border-color: #{$primary-700}; + --bs-btn-hover-color: #{$white}; + } +} + +.header-nav-link.active a { + box-shadow: 0 5px $black; +} + +#header-entry-point-primary { + background-image: #{icon-primary-navigation($black)}; + + &:hover { + background-image: #{icon-primary-navigation($white)}; + } +} + +#header-entry-point-search { + background-image: #{icon-search($black)}; + + &:hover { + background-image: #{icon-search($white)}; + } +} + +#header-entry-point-language { + background-image: #{icon-language($black)}; + + &:hover { + background-image: #{icon-language($white)}; + } +} + +@include media-breakpoint-up(md) { + #nav-primary { + display: block; + } + + .nav-primary-links { + display: flex; + flex-direction: row; + } +} diff --git a/raspberry-mint-dev/src/css/components/modal.scss b/raspberry-mint-dev/src/css/components/modal.scss new file mode 100644 index 000000000..a9fbb1bf3 --- /dev/null +++ b/raspberry-mint-dev/src/css/components/modal.scss @@ -0,0 +1,3 @@ +.modal-header .btn-close { + padding: 0; +} diff --git a/raspberry-mint-dev/src/css/components/references.scss b/raspberry-mint-dev/src/css/components/references.scss new file mode 100644 index 000000000..0ac43193e --- /dev/null +++ b/raspberry-mint-dev/src/css/components/references.scss @@ -0,0 +1,5 @@ +.reference { + &:target { + background-color: $focus; + } +} diff --git a/raspberry-mint-dev/src/css/components/section.scss b/raspberry-mint-dev/src/css/components/section.scss new file mode 100644 index 000000000..14e340a01 --- /dev/null +++ b/raspberry-mint-dev/src/css/components/section.scss @@ -0,0 +1,31 @@ +.section { + &:target { + box-shadow: -$border-width 0 0 0 $focus; + } + + .section-permalink { + box-shadow: none; + display: inline-block; + + &:hover .section-permalink-wrapper { + background-color: var(--bs-link-hover-color); + } + + &:focus { + background-color: $focus; + box-shadow: 0 0 $focus, 0 2px $black; + + .section-permalink-wrapper { + background-color: $black; + } + } + + .section-permalink-wrapper { + background-color: var(--bs-link-color); + display: block; + height: 0.75em; + mask-image: icon-link($black); + width: 0.75em; + } + } +} diff --git a/raspberry-mint-dev/src/css/custom.scss b/raspberry-mint-dev/src/css/custom.scss new file mode 100644 index 000000000..2ad8370bc --- /dev/null +++ b/raspberry-mint-dev/src/css/custom.scss @@ -0,0 +1,31 @@ +/* Bootstrap styles */ +@import "bootstrap/scss/accordion"; +@import "bootstrap/scss/buttons"; +@import "bootstrap/scss/card"; +@import "bootstrap/scss/close"; +@import "bootstrap/scss/forms/labels"; +@import "bootstrap/scss/forms/form-text"; +@import "bootstrap/scss/forms/form-control"; +@import "bootstrap/scss/forms/form-check"; +@import "bootstrap/scss/list-group"; +@import "bootstrap/scss/modal"; +@import "bootstrap/scss/nav"; +@import "bootstrap/scss/navbar"; +@import "bootstrap/scss/transitions"; + +/* Raspberry Mint styles */ +@import "./text"; +@import "./components/accordion"; +@import "./components/button"; +@import "./components/card"; +@import "./components/close"; +@import "./components/header"; +@import "./components/form"; +@import "./components/form-check"; +@import "./components/form-control-text"; +@import "./components/modal"; +@import "./components/references"; +@import "./components/section"; + +/* @todo Do not migrate this to the final product! */ +@import "./dev"; \ No newline at end of file diff --git a/raspberry-mint-dev/src/css/dev.scss b/raspberry-mint-dev/src/css/dev.scss new file mode 100644 index 000000000..27a7a9916 --- /dev/null +++ b/raspberry-mint-dev/src/css/dev.scss @@ -0,0 +1,149 @@ +/* @todo Do not migrate these to the final product! */ +code { + color: #000 !important; + background-color: #fff; +} + +.bg-primary-100 { + background-color: $primary-100 !important; +} + +.bg-primary-200 { + background-color: $primary-200 !important; +} + +.bg-primary-300 { + background-color: $primary-300 !important; +} + +.bg-primary-400 { + background-color: $primary-400 !important; +} + +.bg-primary-500 { + background-color: $primary-500 !important; +} + +.bg-primary-600 { + background-color: $primary-600 !important; +} + +.bg-primary-700 { + background-color: $primary-700 !important; +} + +.bg-primary-800 { + background-color: $primary-800 !important; +} + +.bg-primary-900 { + background-color: $primary-900 !important; +} + +.bg-secondary-100 { + background-color: $secondary-100 !important; +} + +.bg-secondary-200 { + background-color: $secondary-200 !important; +} + +.bg-secondary-300 { + background-color: $secondary-300 !important; +} + +.bg-secondary-400 { + background-color: $secondary-400 !important; +} + +.bg-secondary-500 { + background-color: $secondary-500 !important; +} + +.bg-secondary-600 { + background-color: $secondary-600 !important; +} + +.bg-secondary-700 { + background-color: $secondary-700 !important; +} + +.bg-secondary-800 { + background-color: $secondary-800 !important; +} + +.bg-secondary-900 { + background-color: $secondary-900 !important; +} + +.bg-tertiary-100 { + background-color: $tertiary-100 !important; +} + +.bg-tertiary-200 { + background-color: $tertiary-200 !important; +} + +.bg-tertiary-300 { + background-color: $tertiary-300 !important; +} + +.bg-tertiary-400 { + background-color: $tertiary-400 !important; +} + +.bg-tertiary-500 { + background-color: $tertiary-500 !important; +} + +.bg-tertiary-600 { + background-color: $tertiary-600 !important; +} + +.bg-tertiary-700 { + background-color: $tertiary-700 !important; +} + +.bg-tertiary-800 { + background-color: $tertiary-800 !important; +} + +.bg-tertiary-900 { + background-color: $tertiary-900 !important; +} + +.bg-gray-100 { + background-color: $gray-100 !important; +} + +.bg-gray-200 { + background-color: $gray-200 !important; +} + +.bg-gray-300 { + background-color: $gray-300 !important; +} + +.bg-gray-400 { + background-color: $gray-400 !important; +} + +.bg-gray-500 { + background-color: $gray-500 !important; +} + +.bg-gray-600 { + background-color: $gray-600 !important; +} + +.bg-gray-700 { + background-color: $gray-700 !important; +} + +.bg-gray-800 { + background-color: $gray-800 !important; +} + +.bg-gray-900 { + background-color: $gray-900 !important; +} \ No newline at end of file diff --git a/raspberry-mint-dev/src/css/functions.scss b/raspberry-mint-dev/src/css/functions.scss new file mode 100644 index 000000000..add412b14 --- /dev/null +++ b/raspberry-mint-dev/src/css/functions.scss @@ -0,0 +1 @@ +@import "./functions/icons"; diff --git a/raspberry-mint-dev/src/css/functions/icons.scss b/raspberry-mint-dev/src/css/functions/icons.scss new file mode 100644 index 000000000..aefc7fddd --- /dev/null +++ b/raspberry-mint-dev/src/css/functions/icons.scss @@ -0,0 +1,27 @@ +@function icon-chevron-collapse($color) { + @return url('data:image/svg+xml;utf8,'); +} + +@function icon-chevron-expand($color) { + @return url('data:image/svg+xml;utf8,'); +} + +@function icon-close($color) { + @return url('data:image/svg+xml;utf8,'); +} + +@function icon-language($color) { + @return url('data:image/svg+xml;utf8,'); +} + +@function icon-link($color) { + @return url('data:image/svg+xml;utf8,'); +} + +@function icon-primary-navigation($color) { + @return url('data:image/svg+xml;utf8,'); +} + +@function icon-search($color) { + @return url('data:image/svg+xml;utf8,'); +} diff --git a/raspberry-mint-dev/src/css/main.scss b/raspberry-mint-dev/src/css/main.scss new file mode 100644 index 000000000..e09f3d332 --- /dev/null +++ b/raspberry-mint-dev/src/css/main.scss @@ -0,0 +1,34 @@ +/* This file follows "Option B" from https://getbootstrap.com/docs/5.3/customize/sass/ */ + +// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc) +@import "bootstrap/scss/functions"; +@import "./functions"; + +// 2. Include any default variable overrides here +@import "./variables"; + +// 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets) +@import "bootstrap/scss/variables"; + +// 4. Include any default map overrides here +@import "./maps"; + +// 5. Include remainder of required parts +@import "bootstrap/scss/maps"; +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/root"; + +// 6. Optionally include any other parts as needed +@import "bootstrap/scss/utilities"; +@import "bootstrap/scss/reboot"; +@import "bootstrap/scss/type"; +@import "bootstrap/scss/images"; +@import "bootstrap/scss/containers"; +@import "bootstrap/scss/grid"; +@import "bootstrap/scss/helpers"; + +// 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss` +@import "bootstrap/scss/utilities/api"; + +// 8. Add additional custom code here +@import "./custom"; diff --git a/raspberry-mint-dev/src/css/maps.scss b/raspberry-mint-dev/src/css/maps.scss new file mode 100644 index 000000000..e96e64ce1 --- /dev/null +++ b/raspberry-mint-dev/src/css/maps.scss @@ -0,0 +1,5 @@ +$theme-colors: ( + "primary": $primary, + "secondary": $secondary, + "danger": $tertiary, +); diff --git a/raspberry-mint-dev/src/css/text.scss b/raspberry-mint-dev/src/css/text.scss new file mode 100644 index 000000000..c00bae077 --- /dev/null +++ b/raspberry-mint-dev/src/css/text.scss @@ -0,0 +1,26 @@ +a { + box-shadow: 0 2px var(--betty-link-underline-color); + text-decoration: none; + + &:focus { + background-color: $focus; + box-shadow: 0 0 $focus, 0 2px $black; + color: $black !important; + text-decoration-color: $black; + outline: none; + } + + &:hover { + box-shadow: 0 2px var(--betty-link-hover-underline-color); + } +} + +::selection { + background-color: $selection; + color: $black !important; +} + +.private { + cursor: help; + text-decoration: dotted underline; +} diff --git a/raspberry-mint-dev/src/css/variables.scss b/raspberry-mint-dev/src/css/variables.scss new file mode 100644 index 000000000..9e4ad2af0 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables.scss @@ -0,0 +1,11 @@ +@import "./variables/colors"; +@import "./variables/border"; +@import "./variables/close"; +@import "./variables/spacing"; +@import "./variables/focus"; +@import "./variables/accordion"; +@import "./variables/form"; +@import "./variables/form-check"; +@import "./variables/form-control"; +@import "./variables/font"; +@import "./variables/modal"; diff --git a/raspberry-mint-dev/src/css/variables/accordion.scss b/raspberry-mint-dev/src/css/variables/accordion.scss new file mode 100644 index 000000000..dc5c7707d --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/accordion.scss @@ -0,0 +1,9 @@ +$accordion-button-active-bg: none; +$accordion-button-active-color: inherit; +$accordion-button-active-icon: icon-chevron-collapse($accordion-icon-color); +$accordion-button-icon: icon-chevron-expand($accordion-icon-color); +$accordion-button-padding-y: 0; +$accordion-button-padding-x: 0; +$accordion-border-width: 0; +$accordion-icon-transform: rotateX(-180deg); +$accordion-icon-width: 1.5em; diff --git a/raspberry-mint-dev/src/css/variables/border.scss b/raspberry-mint-dev/src/css/variables/border.scss new file mode 100644 index 000000000..7da616fae --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/border.scss @@ -0,0 +1,7 @@ +$border-radius: 0; +$border-radius-sm: 0; +$border-radius-lg: 0; +$border-radius-xl: 0; +$border-radius-xxl: 0; +$border-radius-pill: 0; +$border-width: 3px; diff --git a/raspberry-mint-dev/src/css/variables/close.scss b/raspberry-mint-dev/src/css/variables/close.scss new file mode 100644 index 000000000..a4c0a87f0 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/close.scss @@ -0,0 +1,6 @@ +$btn-close-bg: #{icon-close($black)}; +$btn-close-focus-opacity: 1; +$btn-close-hover-opacity: 1; +$btn-close-opacity: 1; +$btn-close-padding-x: 0; +$btn-close-width: 2rem; diff --git a/raspberry-mint-dev/src/css/variables/colors.scss b/raspberry-mint-dev/src/css/variables/colors.scss new file mode 100644 index 000000000..e0ae3aac8 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/colors.scss @@ -0,0 +1,245 @@ +/** Base colors */ +$mint: #3eb489; +$raspberry: #b3446c; +$orange: #ffbd22; +$gray: #808080; + +/* Mint shades */ +$mint-100: mix(white, $mint, 80%); +$mint-200: mix(white, $mint, 60%); +$mint-300: mix(white, $mint, 40%); +$mint-400: mix(white, $mint, 20%); +$mint-500: $mint; +$mint-600: mix(black, $mint, 20%); +$mint-700: mix(black, $mint, 40%); +$mint-800: mix(black, $mint, 60%); +$mint-900: mix(black, $mint, 80%); + +/* Raspberry shades */ +$raspberry-100: mix(white, $raspberry, 80%); +$raspberry-200: mix(white, $raspberry, 60%); +$raspberry-300: mix(white, $raspberry, 40%); +$raspberry-400: mix(white, $raspberry, 20%); +$raspberry-500: $raspberry; +$raspberry-600: mix(black, $raspberry, 20%); +$raspberry-700: mix(black, $raspberry, 40%); +$raspberry-800: mix(black, $raspberry, 60%); +$raspberry-900: mix(black, $raspberry, 80%); + +/* Orange shades */ +$orange-100: mix(white, $orange, 80%); +$orange-200: mix(white, $orange, 60%); +$orange-300: mix(white, $orange, 40%); +$orange-400: mix(white, $orange, 20%); +$orange-500: $orange; +$orange-600: mix(black, $orange, 20%); +$orange-700: mix(black, $orange, 40%); +$orange-800: mix(black, $orange, 60%); +$orange-900: mix(black, $orange, 80%); + +/* Gray shades */ +$gray-100: mix(white, $gray, 80%); +$gray-200: mix(white, $gray, 60%); +$gray-300: mix(white, $gray, 40%); +$gray-400: mix(white, $gray, 20%); +$gray-500: $gray; +$gray-600: mix(black, $gray, 20%); +$gray-700: mix(black, $gray, 40%); +$gray-800: mix(black, $gray, 60%); +$gray-900: mix(black, $gray, 80%); + +/* Black and white */ +$black: #000; +$white: #fff; + +/* Primary color shades (these are configurable) */ +$primary: $raspberry; +$primary-100: $raspberry-100; +$primary-200: $raspberry-200; +$primary-300: $raspberry-300; +$primary-400: $raspberry-400; +$primary-500: $raspberry-500; +$primary-600: $raspberry-600; +$primary-700: $raspberry-700; +$primary-800: $raspberry-800; +$primary-900: $raspberry-900; + +/* Secondary color shades (these are configurable) */ +$secondary: $mint; +$secondary-100: $mint-100; +$secondary-200: $mint-200; +$secondary-300: $mint-300; +$secondary-400: $mint-400; +$secondary-500: $mint-500; +$secondary-600: $mint-600; +$secondary-700: $mint-700; +$secondary-800: $mint-800; +$secondary-900: $mint-900; + +/* Tertiary color shades (these are configurable) */ +$tertiary: $orange; +$tertiary-100: $orange-100; +$tertiary-200: $orange-200; +$tertiary-300: $orange-300; +$tertiary-400: $orange-400; +$tertiary-500: $orange-500; +$tertiary-600: $orange-600; +$tertiary-700: $orange-700; +$tertiary-800: $orange-800; +$tertiary-900: $orange-900; + +/* Color modes */ + +// Single definitions and overrides. +$focus: $tertiary-300; +$selection: $tertiary-100; +$accordion-icon-color: $black; +$accordion-icon-active-color: $black; + + +// $body-bg +$body-bg: $white; +$body-bg-dark: $black; +$body-bg-light-primary: $primary-100; +$body-bg-dark-primary: $primary-900; +$body-bg-light-secondary: $secondary-100; +$body-bg-dark-secondary: $secondary-900; + +// $body-color +$body-color: $black; +$body-color-dark: $white; + +// $link-color +$link-color: $secondary-800; +$link-color-dark: $secondary-200; +$link-color-light-primary: $primary-800; +$link-color-dark-primary: $primary-200; +$link-color-light-secondary: $secondary-800; +$link-color-dark-secondary: $secondary-200; + +// $link-hover-color +$link-hover-color: $secondary-900; +$link-hover-color-dark: $secondary-100; +$link-hover-color-light-primary: $primary-900; +$link-hover-color-dark-primary: $primary-100; +$link-hover-color-light-secondary: $secondary-900; +$link-hover-color-dark-secondary: $secondary-100; + +// $link-underline-color +$link-underline-color: $secondary-600; +$link-underline-color-dark: $secondary-400; +$link-underline-color-light-primary: $primary-600; +$link-underline-color-dark-primary: $primary-400; +$link-underline-color-light-secondary: $secondary-600; +$link-underline-color-dark-secondary: $secondary-400; + +// $link-hover-underline-color +$link-hover-underline-color: $secondary-700; +$link-hover-underline-color-dark: $secondary-300; +$link-hover-underline-color-light-primary: $primary-700; +$link-hover-underline-color-dark-primary: $primary-300; +$link-hover-underline-color-light-secondary: $secondary-700; +$link-hover-underline-color-dark-secondary: $secondary-300; + + +// Betty CSS variables +body { + --betty-link-underline-color: #{$link-underline-color}; + --betty-link-hover-underline-color: #{$link-hover-underline-color}; +} + +// $card-bg +$card-bg: $gray-100; +$card-bg-dark: $white; + +// $card-color +$card-color: $black; +$card-color-dark: $white; + +@mixin common { + --bs-card-bg: #{$white}; +} + +@mixin light { + @include common; + + --bs-body-color: #{$body-color}; + --bs-body-color-rgb: #{to-rgb($body-color)}; + --bs-card-color: #{$card-color} !important; + + color: #{$card-color} !important; +} + +@mixin dark { + @include common; + + --betty-link-underline-color: #{$link-underline-color-dark}; + --betty-link-hover-underline-color: #{$link-hover-underline-color-dark}; + --bs-body-color: #{$body-color-dark}; + --bs-body-color-rgb: #{to-rgb($body-color-dark)}; + --bs-card-color: #{$card-color-dark} !important; + + color: #{$card-color-dark} !important; +} + +[data-bs-theme="dark"] { + @include dark; + + background-color: #{$body-bg-dark} !important; +} + +[data-bs-theme="light-primary"] { + @include light; + + --betty-link-underline-color: #{$link-underline-color-light-primary}; + --betty-link-hover-underline-color: #{$link-hover-underline-color-light-primary}; + --bs-link-color: #{$link-color-light-primary}; + --bs-link-color-rgb: #{to-rgb($link-color-light-primary)}; + --bs-link-hover-color: #{$link-hover-color-light-primary}; + --bs-link-hover-color-rgb: #{to-rgb($link-hover-color-light-primary)}; + + background-color: #{$body-bg-light-primary} !important; + color-scheme: light; +} + +[data-bs-theme="dark-primary"] { + @include dark; + + --betty-link-underline-color: #{$link-underline-color-dark-primary}; + --betty-link-hover-underline-color: #{$link-hover-underline-color-dark-primary}; + --bs-link-color: #{$link-color-dark-primary}; + --bs-link-color-rgb: #{to-rgb($link-color-dark-primary)}; + --bs-link-hover-color: #{$link-hover-color-dark-primary}; + --bs-link-hover-color-rgb: #{to-rgb($link-hover-color-dark-primary)}; + + background-color: #{$body-bg-dark-primary} !important; + color-scheme: dark; +} + +[data-bs-theme="light-secondary"] { + @include light; + + --betty-link-underline-color: #{$link-underline-color-light-secondary}; + --betty-link-hover-underline-color: #{$link-hover-underline-color-light-secondary}; + --bs-link-color: #{$link-color-light-secondary}; + --bs-link-color-rgb: #{to-rgb($link-color-light-secondary)}; + --bs-link-hover-color: #{$link-hover-color-light-secondary}; + --bs-link-hover-color-rgb: #{to-rgb($link-hover-color-light-secondary)}; + + background-color: #{$body-bg-light-secondary} !important; + color-scheme: light; +} + +[data-bs-theme="dark-secondary"] { + @include dark; + + --betty-link-underline-color: #{$link-underline-color-dark-secondary}; + --betty-link-hover-underline-color: #{$link-hover-underline-color-dark-secondary}; + --bs-link-color: #{$link-color-dark-secondary}; + --bs-link-color-rgb: #{to-rgb($link-color-dark-secondary)}; + --bs-link-hover-color: #{$link-hover-color-dark-secondary}; + --bs-link-hover-color-rgb: #{to-rgb($link-hover-color-dark-secondary)}; + + background-color: #{$body-bg-dark-secondary} !important; + color-scheme: dark; +} \ No newline at end of file diff --git a/raspberry-mint-dev/src/css/variables/focus.scss b/raspberry-mint-dev/src/css/variables/focus.scss new file mode 100644 index 000000000..6323dedf6 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/focus.scss @@ -0,0 +1,4 @@ +$focus-ring-width: 0; +$focus-ring-opacity: 1; +$focus-ring-blur: 0; +$focus-ring-box-shadow: 0; diff --git a/raspberry-mint-dev/src/css/variables/font.scss b/raspberry-mint-dev/src/css/variables/font.scss new file mode 100644 index 000000000..93fa7e0eb --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/font.scss @@ -0,0 +1,3 @@ +$font-family-base: "Noto Sans", system-ui, -apple-system, "Segoe UI", "Roboto", "Helvetica Neue", "Liberation Sans", "Arial", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +$font-size-base: 1.3rem; +$small-font-size: 0.9em; diff --git a/raspberry-mint-dev/src/css/variables/form-check.scss b/raspberry-mint-dev/src/css/variables/form-check.scss new file mode 100644 index 000000000..c6a41e2b0 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/form-check.scss @@ -0,0 +1,6 @@ +$form-check-input-border: $border-width solid $form-element-border-color; +$form-check-input-border-radius: 0; +$form-check-input-checked-color: $black; +$form-check-input-checked-bg-color: white; +$form-check-input-checked-border-color: $form-element-border-color; +$form-check-input-width: 1.5em; diff --git a/raspberry-mint-dev/src/css/variables/form-control.scss b/raspberry-mint-dev/src/css/variables/form-control.scss new file mode 100644 index 000000000..218b4a577 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/form-control.scss @@ -0,0 +1,4 @@ +$input-border-color: $form-element-border-color; +$input-focus-bg: $focus; +$input-focus-border-color: $black; +$input-placeholder-color: $gray-500; diff --git a/raspberry-mint-dev/src/css/variables/form.scss b/raspberry-mint-dev/src/css/variables/form.scss new file mode 100644 index 000000000..ed871dc14 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/form.scss @@ -0,0 +1 @@ +$form-element-border-color: $gray-900; diff --git a/raspberry-mint-dev/src/css/variables/modal.scss b/raspberry-mint-dev/src/css/variables/modal.scss new file mode 100644 index 000000000..8be6674f0 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/modal.scss @@ -0,0 +1,7 @@ +@use "sass:map"; + +$modal-backdrop-opacity: .7; +$modal-content-border-width: 0; +$modal-header-border-width: 0; +$modal-header-padding-x: $spacer; +$modal-header-padding-y: $spacer * .25; diff --git a/raspberry-mint-dev/src/css/variables/spacing.scss b/raspberry-mint-dev/src/css/variables/spacing.scss new file mode 100644 index 000000000..732a04cc5 --- /dev/null +++ b/raspberry-mint-dev/src/css/variables/spacing.scss @@ -0,0 +1 @@ +$spacer: 2rem; diff --git a/raspberry-mint-dev/src/js/main.ts b/raspberry-mint-dev/src/js/main.ts new file mode 100644 index 000000000..ec17c08ae --- /dev/null +++ b/raspberry-mint-dev/src/js/main.ts @@ -0,0 +1,3 @@ +import '../css/main.scss' +import "bootstrap/js/dist/collapse" +import "bootstrap/js/dist/modal" diff --git a/raspberry-mint-dev/src/www/index.html b/raspberry-mint-dev/src/www/index.html new file mode 100644 index 000000000..7c8ec455e --- /dev/null +++ b/raspberry-mint-dev/src/www/index.html @@ -0,0 +1,666 @@ + + + + Raspberry Mint development environment + + + + + + + + +
+ Skip to main content +
+
+
+ +
+
+ + + +
+
+
+
+
+

Welcome to Betty's new theme: Raspberry Mint +

+
+
+
+
+

+ Construction scheduled until + Spring 2025 +

+
+
+

+ Follow the development +

+
+
+
+
+
+

+ Try it out now: pip install git+https://github.com/bartfeenstra/betty.git@raspberry-mint +

+
+
+
+
+
+

Colors Permanent link to this section.

+ +

+ An evolution of the colors introduced by Betty's original theme, Cotton Candy, combined + with a fresh, new, third color to help guide user interactions. All colors come in nine predefined + shades. +

+
+
+
    +
  • $raspberry
  • +
  • $mint
  • +
  • $orange
  • +
+
+
+ +
+
+

Raspberry

+

+ The primary color, used to call for attention or indicate actions. +

+
    +
  • $raspberry-100
  • +
  • $raspberry-200
  • +
  • $raspberry-300
  • +
  • $raspberry-400
  • +
  • $raspberry-500
  • +
  • $raspberry-600
  • +
  • $raspberry-700
  • +
  • $raspberry-800
  • +
  • $raspberry-900
  • +
+
+ +
+

Mint

+

+ The secondary color. Among other things, used for navigation. +

+
    +
  • $mint-100
  • +
  • $mint-200
  • +
  • $mint-300
  • +
  • $mint-400
  • +
  • $mint-500
  • +
  • $mint-600
  • +
  • $mint-700
  • +
  • $mint-800
  • +
  • $mint-900
  • +
+
+ +
+

Orange

+

+ The tertiary color. Used when a contrasting color is desired, usually to communicate an interaction + state to the user, such as highlights, or which element on the page is currently + focused. +

+
    +
  • $orange-100
  • +
  • $orange-200
  • +
  • $orange-300
  • +
  • $orange-400
  • +
  • $orange-500
  • +
  • $orange-600
  • +
  • $orange-700
  • +
  • $orange-800
  • +
  • $orange-900
  • +
+
+ +
+

Gray

+
    +
  • $gray-100
  • +
  • $gray-200
  • +
  • $gray-300
  • +
  • $gray-400
  • +
  • $gray-500
  • +
  • $gray-600
  • +
  • $gray-700
  • +
  • $gray-800
  • +
  • $gray-900
  • +
+
+ +
+

Black and white

+
    +
  • $black
  • +
  • $white
  • +
+
+
+
+ +
+

Text Permanent link to this section.

+ +
+

Paragraph Permanent link to this section.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas risus mi, aliquam eget bibendum id, + venenatis et leo. Suspendisse potenti. Orci varius natoque penatibus et magnis dis parturient montes, + nascetur ridiculus mus. Morbi ultricies dapibus mauris. Ut cursus pharetra nibh, ut venenatis tellus. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam erat volutpat. Vestibulum bibendum, ex + sed convallis egestas, erat leo venenatis eros, vel elementum mauris tortor a arcu. Aenean bibendum + malesuada elit. Pellentesque eleifend, mi sit amet molestie congue, augue metus volutpat lacus, eu + posuere mauris turpis sed turpis. Proin pulvinar finibus orci sit amet consectetur. Quisque scelerisque + tempus dui ac fermentum.

+

Donec ac nunc ligula. Sed sit amet metus in diam tincidunt condimentum. Phasellus sodales odio nec arcu + tempus cursus. Aenean fermentum purus eros, molestie tincidunt magna tincidunt sed. Proin sagittis ut ex + in luctus. Suspendisse potenti. Donec sed ullamcorper metus. Morbi sed quam eget tortor commodo + congue.

+

Nam quis est est. Ut pellentesque at ligula sit amet venenatis. Phasellus id consectetur tortor. Cras + odio erat, tristique dapibus dapibus in, convallis at orci. Sed magna tortor, ultrices nec posuere quis, + gravida vel lorem. Nulla tincidunt nec neque non bibendum. Aenean finibus erat sit amet pulvinar + posuere. Cras tellus erat, imperdiet nec dolor at, egestas laoreet ante. In eget orci quis ligula porta + placerat et at quam. Morbi fringilla condimentum magna, in ornare ligula aliquam quis.

+
+ + + +
+

References

+

Lorem ipsum dolor sit amet [1].

+

Donec ac nunc ligula [1] [2].

+
+ +
+

Scripts Permanent link to this section.

+ +
+
+
+
+

Arabic

+

مرحباً بكم في Betty!

+
+
+
+
+
+
+

Chinese, traditional (Cantonese)

+

歡迎嚟到 Betty!

+
+
+
+
+
+
+

Hebrew

+

ברוכים הבאים לBetty! +

+
+
+
+
+
+
+

Cyrillic (Ukrainian)

+

Ласкаво просимо до Betty!

+
+
+
+
+
+
+ +
+

Components Permanent link to this section.

+ +
+

Cards Permanent link to this section.

+ +
+
+
+

Light

+

The quick brown fox jumps over the lazy dog.

+ Card link + Another link +
+
+
+ +
+
+
+

Dark

+

The quick brown fox jumps over the lazy dog.

+ Card link + Another link +
+
+
+ +
+
+
+

Light Primary

+

The quick brown fox jumps over the lazy dog.

+ Card link + Another link +
+
+
+ +
+
+
+

Dark Primary

+

The quick brown fox jumps over the lazy dog.

+ Card link + Another link +
+
+
+ +
+
+
+

Light Secondary

+

The quick brown fox jumps over the lazy dog.

+ Card link + Another link +
+
+
+ +
+
+
+

Dark Secondary

+

The quick brown fox jumps over the lazy dog.

+ Card link + Another link +
+
+
+
+ +
+

Forms Permanent link to this section.

+ +
+
+

Button Permanent link to this section.

+ + +
+ +
+

Checkbox Permanent link to this section.

+
+ + +
+
+ +
+

Checkboxes Permanent link to this section.

+
+ Check these out! +
+ + +
+
+ + +
+
+
+ +
+

Radio button Permanent link to this section.

+ +
+ Check these out! +
+ + +
+
+ + +
+
+
+ +
+

Text input Permanent link to this section.

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

Accordion Permanent link to this section.

+
+
+

+ +

+
+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas risus mi, aliquam + eget bibendum id, venenatis et leo. Suspendisse potenti. Orci varius natoque + penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi ultricies + dapibus mauris. Ut cursus pharetra nibh, ut venenatis tellus. Lorem ipsum dolor sit + amet, consectetur adipiscing elit. Aliquam erat volutpat. Vestibulum bibendum, ex + sed convallis egestas, erat leo venenatis eros, vel elementum mauris tortor a arcu. + Aenean bibendum malesuada elit. Pellentesque eleifend, mi sit amet molestie congue, + augue metus volutpat lacus, eu posuere mauris turpis sed turpis. Proin pulvinar + finibus orci sit amet consectetur. Quisque scelerisque tempus dui ac fermentum.

+
+
+
+
+

+ +

+
+
+

Donec ac nunc ligula. Sed sit amet metus in diam tincidunt condimentum. Phasellus + sodales odio nec arcu tempus cursus. Aenean fermentum purus eros, molestie tincidunt + magna tincidunt sed. Proin sagittis ut ex in luctus. Suspendisse potenti. Donec sed + ullamcorper metus. Morbi sed quam eget tortor commodo congue.

+
+
+
+
+

+ +

+
+
+

Nam quis est est. Ut pellentesque at ligula sit amet venenatis. Phasellus id + consectetur tortor. Cras odio erat, tristique dapibus dapibus in, convallis at orci. + Sed magna tortor, ultrices nec posuere quis, gravida vel lorem. Nulla tincidunt nec + neque non bibendum. Aenean finibus erat sit amet pulvinar posuere. Cras tellus erat, + imperdiet nec dolor at, egestas laoreet ante. In eget orci quis ligula porta + placerat et at quam. Morbi fringilla condimentum magna, in ornare ligula aliquam + quis.

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

References Permanent link to this section.

+
    +
  1. + + "Personal accounts". + First-person account. + +
  2. +
  3. + + Gemeente Amsterdam. + "Bevolkingsregister Amsterdam". + Amsterdam, + private. + +
  4. +
  5. + + Gemeente Ilpendam. + "Bevolkingsregister Ilpendam". + Ilpendam, + Civil registry, Ilpendam, 1924-1939, 43a-43b, sheet 566. + +
  6. +
  7. + + private. + +
  8. +
  9. + + "Personal accounts". + Second-person account. + +
  10. +
  11. + + private. + +
  12. +
+
+
+
+
+
+
+
+

+ © Copyright Bart Feenstra, unless otherwise credited +

+

+ All rights reserved +

+

+ Contact me at bart@bartfeenstra.com +

+
+
+

+ Last modified on + +

+

+ API documentation +

+
+
+
+
+ + A family history as told by Betty + +
+
+
+
+ + diff --git a/raspberry-mint-dev/webpack.config.js b/raspberry-mint-dev/webpack.config.js new file mode 100644 index 000000000..ea3397f60 --- /dev/null +++ b/raspberry-mint-dev/webpack.config.js @@ -0,0 +1,136 @@ +'use strict' + +import {CleanWebpackPlugin} from 'clean-webpack-plugin' +import CopyWebpackPlugin from 'copy-webpack-plugin' +import CssMinimizerPlugin from 'css-minimizer-webpack-plugin' +import HtmlWebpackPlugin from 'html-webpack-plugin' +import MiniCssExtractPlugin from 'mini-css-extract-plugin' +import path from 'path' +import TerserPlugin from 'terser-webpack-plugin' +import url from 'node:url' + +const __dirname = url.fileURLToPath(new URL('.', import.meta.url)) + +const webpackConfiguration = { + mode: 'development', + devtool: 'eval-source-map', + entry: path.join(__dirname, 'src', 'js', 'main.ts'), + output: { + path: path.join(__dirname, 'build'), + filename: 'js/[name].js' + }, + /* @todo Do not migrate this to the final product! */ + devServer: { + watchFiles: { + paths: [ + "./src/**/*" + ], + } + }, + optimization: { + concatenateModules: true, + minimize: false, + minimizer: [ + new CssMinimizerPlugin(), + new TerserPlugin({ + extractComments: false, + terserOptions: { + output: { + comments: false + } + } + }) + ], + }, + plugins: [ + new CleanWebpackPlugin(), + new MiniCssExtractPlugin({ + filename: 'css/[name].css' + }), + new HtmlWebpackPlugin({template: path.join(__dirname, './src/www/index.html')}), + new CopyWebpackPlugin({ + patterns: [ + { + from: path.join(__dirname, '../betty/assets/public/static/betty-192x192.png'), + to: './images/', + } + ], + }) + + ], + module: { + rules: [ + { + test: /\.(js|ts)$/, + exclude: /node_modules/, + use: [ + { + loader: 'babel-loader', + options: { + cacheDirectory: path.resolve(__dirname, 'cache'), + presets: [ + [ + '@babel/preset-env', { + debug: true, + modules: false, + useBuiltIns: 'usage', + corejs: 3 + }, + ], + '@babel/preset-typescript', + ] + } + } + ] + }, + { + test: /\.s?css$/, + use: [ + { + loader: MiniCssExtractPlugin.loader, + options: { + publicPath: '/' + } + }, + { + loader: 'css-loader', + options: { + url: { + // Betty's own assets are generated through the assets file system, + // so we use Webpack for vendor assets only. + filter: (url, resourcePath) => resourcePath.includes('/node_modules/'), + } + } + }, + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: () => [ + require('autoprefixer') + ] + } + } + }, + { + loader: 'sass-loader', + options: { + sassOptions: { + silenceDeprecations: ["color-functions", "global-builtin", "import", "mixed-decls"] + } + } + } + ] + }, + { + test: /.*\.png|gif|jpg|jpeg|svg/, + type: 'asset/resource', + generator: { + filename: 'images/[hash][ext]' + } + } + ] + } +} + +export default webpackConfiguration