support dark-mode

This commit is contained in:
2023-04-25 19:24:20 +10:00
parent bc2a25346b
commit 2168e693d8
39 changed files with 464 additions and 625 deletions

View File

@@ -10,6 +10,6 @@
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
<g transform="translate(0,-290.65)"> <g transform="translate(0,-290.65)">
<path transform="matrix(.26458 0 0 .26458 0 290.65)" d="m4 3c-1.108 0-2 0.89201-2 2s0.89201 2 2 2h16c1.108 0 2-0.89201 2-2s-0.89202-2-2-2h-16zm0 6.7773c-1.108 0-2 0.94178-2 2.1113s0.89201 2.1113 2 2.1113h16c1.108 0 2-0.94178 2-2.1113s-0.89201-2.1113-2-2.1113h-16zm0 7c-1.108 0-2 0.94178-2 2.1113s0.89203 2.1113 2 2.1113h16c1.108 0 2-0.94178 2-2.1113s-0.89203-2.1113-2-2.1113h-16z" fill="#333"/> <path transform="matrix(.26458 0 0 .26458 0 290.65)" d="m4 3c-1.108 0-2 0.89201-2 2s0.89201 2 2 2h16c1.108 0 2-0.89201 2-2s-0.89202-2-2-2h-16zm0 6.7773c-1.108 0-2 0.94178-2 2.1113s0.89201 2.1113 2 2.1113h16c1.108 0 2-0.94178 2-2.1113s-0.89201-2.1113-2-2.1113h-16zm0 7c-1.108 0-2 0.94178-2 2.1113s0.89203 2.1113 2 2.1113h16c1.108 0 2-0.94178 2-2.1113s-0.89203-2.1113-2-2.1113h-16z" fill="color"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 929 B

After

Width:  |  Height:  |  Size: 930 B

View File

@@ -43,33 +43,20 @@ h4,
h5, h5,
h6 { h6 {
font-family: var(--header-font-family); font-family: var(--header-font-family);
font-weight: 800; font-weight: var(--header-font-weight);
margin-bottom: 0; color: var(--header-color-text);
} }
h1 { @for $i from 1 through 6 {
font-size: 42px; h#{$i} {
} font-size: var(--header-font-size-#{$i});
margin-bottom: #{calc(var(--header-font-size-#{$i}) / 2)};
h2 { }
font-size: 36px;
}
h3 {
font-size: 28px;
}
h4 {
font-size: 20px;
}
h5 {
font-size: 16px;
} }
a, a,
a:visited { a:visited {
color: var(--primary-color); color: var(--link-color);
text-decoration-thickness: 0.1em; text-decoration-thickness: 0.1em;
text-decoration-color: var(--primary-color-light); text-decoration-color: var(--primary-color-light);
@@ -86,61 +73,28 @@ li,
} }
p { p {
margin: 1rem 0; margin: #{map-get($spacing, 5)} 0;
} }
li { li {
margin-bottom: 16px; margin-bottom: #{map-get($spacing, 1)};
& + ul { & + ul {
margin-top: -16px; margin-top: -#{map-get($spacing, 1)};
} }
} }
// Who knows why ion-icon randomally sets this to hidden..... code {
// ion-icon { display: block;
// visibility: visible; font-size: 80%;
// } background-color: var(--base-color);
padding: #{map-get($spacing, 3)};
// #app { border: 1px solid var(--base-color-border);
// display: flex; white-space: pre-wrap;
// flex-direction: column; overflow-x: auto;
// min-height: 100vh; max-height: #{calc(map-get($spacing, 7) * 12)};
// } margin-bottom: #{map-get($spacing, 3)};
}
// a,
// a:visited {
// color: $primary-color;
// text-decoration: none;
// transition: color 0.1s, underline 0.1s;
// &:hover {
// color: $primary-color-dark;
// text-decoration: underline;
// }
// }
// h1 {
// text-align: left;
// font-weight: 800;
// }
// p {
// line-height: 1.5rem;
// margin-top: 0;
// }
// code {
// display: block;
// font-size: 0.8rem;
// background-color: #eee;
// padding: 1rem;
// border: 1px solid #ddd;
// white-space: pre-wrap;
// overflow-x: auto;
// max-height: 30rem;
// margin-bottom: 1rem;
// }
/* SM Dialog */ /* SM Dialog */
.dialog-outer { .dialog-outer {
@@ -154,7 +108,7 @@ li {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 1000; z-index: 1000;
padding: 1rem; padding: #{map-get($spacing, 2)};
} }
.dialog-outer:last-of-type { .dialog-outer:last-of-type {

View File

@@ -15,17 +15,17 @@
display: none; display: none;
} }
// @media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
// .dark\:d-none { .dark\:d-none {
// display: none !important; display: none !important;
// } }
// } }
// @media (prefers-color-scheme: light) { @media (prefers-color-scheme: light) {
.light\:d-none { .light\:d-none {
display: none !important; display: none !important;
}
} }
// }
/* Width */ /* Width */
.w-100 { .w-100 {
@@ -134,7 +134,7 @@
} }
/* Padding */ /* Padding */
@each $index, $size in $spacer { @each $index, $size in $spacing {
.p-#{$index} { .p-#{$index} {
padding: #{$size} !important; padding: #{$size} !important;
} }
@@ -167,7 +167,7 @@
} }
/* Margin */ /* Margin */
@each $index, $size in $spacer { @each $index, $size in $spacing {
.m-#{$index} { .m-#{$index} {
margin: #{$size} !important; margin: #{$size} !important;
} }
@@ -258,7 +258,6 @@
small, small,
.small { .small {
font-size: 70%; font-size: 70%;
line-height: 150%;
} }
.italic { .italic {

View File

@@ -1,55 +1,144 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700;800&family=Nunito:wght@400;700;800;1000&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700;800&family=Nunito:wght@400;700;800;1000&display=swap");
:root { :root {
// yes --default-size: 1rem;
--default-font-size: 18px; --default-font-size: var(--default-size);
--default-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, --default-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
// --default-font-family: "Nunito", "Nunito override", "Arial", "Helvetica", }
// sans-serif;
// yes /**
* 0: 0 0px
* 1: 0.25 4px
* 2: 0.5 8px
* 3: 1 16px
* 4: 1.25 20px
* 5: 1.5 24px
* 6: 2 32px
* 7: 2.5 40px
*/
$spacing: (
0: 0,
1: #{calc(var(--default-size) / 4)},
2: #{calc(var(--default-size) / 2)},
3: var(--default-size),
4: #{calc(var(--default-size) * 1.2)},
5: #{calc(var(--default-size) * 1.5)},
6: #{calc(var(--default-size) * 2)},
7: #{calc(var(--default-size) * 2.5)},
);
:root {
// Base
--base-color: #eee; --base-color: #eee;
--base-color-text: #456; --base-color-text: #456;
--base-color-background: #fff;
--base-color-border: #999; --base-color-border: #999;
--base-color-light: #fff; --base-color-light: #fff;
--base-color-lighter: #fff;
--base-color-dark: #ddd; --base-color-dark: #ddd;
--base-color-darker: #999; --base-color-darker: #999;
// yes
--base-shadow: 0 0 4px rgba(0, 0, 0, 0.2); --base-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
--link-color: var(--primary-color); --link-color: var(--primary-color);
--primary-color-lighter: #cce8fb; // Primary
--primary-color-light: #67bbf4;
// yes
--primary-color: #35a5f1; --primary-color: #35a5f1;
--primary-color-hover: #f1fdff; --primary-color-light: #67bbf4;
--primary-color-lighter: #cce8fb;
--primary-color-dark: #0e80ce; --primary-color-dark: #0e80ce;
--primary-color-darker: #095589; --primary-color-darker: #095589;
--danger-color-lighter: #f3c8c8; // Danger
--danger-color-light: #db5c5a;
// yes
--danger-color: #c82e2b; --danger-color: #c82e2b;
--danger-color-light: #db5c5a;
--danger-color-lighter: #f3c8c8;
--danger-color-dark: #952220; --danger-color-dark: #952220;
--danger-color-darker: #641715; --danger-color-darker: #641715;
// yes // Success
--success-color: #198754; --success-color: #198754;
--success-color-light: #26d081;
--success-color-lighter: #b5f1d5;
--success-color-dark: #12653e;
--success-color-darker: #0c4329;
// yes // Warning
--warning-color: #fff3cd; --warning-color: #ffecb5;
--warning-color-light: #fff3cd;
--warning-color-lighter: #fff8e2;
--warning-color-dark: #856404;
--warning-color-darker: #664d03;
// Header
--header-font-family: "Montserrat", "Montserrat override", "Arial", --header-font-family: "Montserrat", "Montserrat override", "Arial",
"Helvetica", sans-serif; "Helvetica", sans-serif;
--header-font-weight: 800;
--header-font-size-1: #{map-get($spacing, 7)};
--header-font-size-2: #{map-get($spacing, 6)};
--header-font-size-3: #{map-get($spacing, 5)};
--header-font-size-4: #{map-get($spacing, 4)};
--header-font-size-5: #{map-get($spacing, 3)};
--header-color-text: var(--base-color-text);
// Buttons
--button-font-family: var(--header-font-family);
--button-font-weight: 600;
--button-color: var(--base-color-light);
--button-color-text: var(--base-color-text);
--button-disabled-color: var(--base-color-dark);
--button-disabled-color-text: var(--base-color-light);
--button-dropdown-color-border: var(--base-color-border);
--button-dropdown-color: var(--base-color-background);
--button-dropdown-color-hover: var(--primary-color-lighter);
--button-primary-color: var(--primary-color);
--button-primary-color-text: var(--base-color-light);
--button-secondary-color: var(--base-color-darker);
--button-secondary-color-text: var(--base-color-light);
--button-danger-color: var(--danger-color);
--button-danger-color-text: var(--base-color-light);
// Card
--card-color: var(--base-color);
--card-color-text: var(--base-color-text);
// Hero
--hero-color-text: #fff;
--hero-caption-color: rgba(0, 0, 0, 0.5);
--hero-caption-color-text: #ddd;
--hero-caption-color-link: #eee;
--hero-shadow: 0 0 8px #000;
// Input
--input-clear-icon-color: var(--base-color-dark);
--input-clear-icon-color-hover: var(--base-color-light);
// Pagination
--pagination-color: var(--base-color-light);
--pagination-color-active: var(--primary-color);
--pagination-color-hover: var(--primary-color);
--pagination-color-disabled: var(--base-color);
--pagination-color-disabled-text: var(--base-color-darker);
// Tab
--tab-color: var(--base-color-light);
--tab-color-text: var(--base-color-text);
--tab-color-border: var(--base-color-border);
// Table
--table-color: var(--base-color-light);
--table-color-even: #f8f8f8;
--table-color-border: var(--base-color-border);
--table-color-hover: var(--table-color);
// Accents
--accent-1-color: #3d4e5d;
--accent-1-color-text: #e6f5eb;
--accent-2-color: #cce8fb;
--accent-2-color-text: #063954;
// SKIP BELOW
--navbar-color: var(--base-color-light); --navbar-color: var(--base-color-light);
--navbar-color-dropdown: var(--base-color-light); --navbar-color-dropdown: var(--base-color-light);
@@ -59,14 +148,6 @@
--footer-color-text: #888; --footer-color-text: #888;
--footer-color-border: rgba(0, 0, 0, 0.1); --footer-color-border: rgba(0, 0, 0, 0.1);
// yes
--accent-1-color: #3d4e5d;
--accent-1-color-text: #e6f5eb;
// yes
--accent-2-color: #cce8fb;
--accent-2-color-text: #063954;
// yes // yes
--banner-yellow-color: #ffd75a; --banner-yellow-color: #ffd75a;
--banner-yellow-color-text: #333; --banner-yellow-color-text: #333;
@@ -78,90 +159,30 @@
--banner-purple-color-text: #fff; --banner-purple-color-text: #fff;
} }
// @media (prefers-color-scheme: dark) { // --primary-color-hover: #f1fdff;
// :root {
// // yes
// --base-color: #222;
// --base-color-text: rgba(255, 255, 255, 0.9);
// --base-color-border: #000;
// --base-color-light: #333;
// // no @media (prefers-color-scheme: dark) {
// --base-color-dark: #444; :root {
// --base-color-darker: #999; // Base
--base-color: #222;
--base-color-text: #ccc;
--base-color-background: #eee;
--base-color-border: #999;
--base-color-light: #333;
--base-color-lighter: #444;
--base-color-dark: #666;
--base-color-darker: #999;
// --footer-color-text: #999; --button-color: var(--base-color-lighter);
// --footer-color-border: rgba(255, 255, 255, 0.1); --button-color-text: var(--base-color-background);
--button-primary-color-text: var(--base-color-background);
--button-secondary-color-text: var(--base-color-background);
--button-danger-color-text: var(--base-color-background);
// --primary-color-lighter: #095589; --footer-color-border: rgba(255, 255, 255, 0.1);
// --primary-color-light: #0e80ce;
// // yes // Accents
// --primary-color: #35a5f1; --accent-2-color: #063954;
--accent-2-color-text: #cce8fb;
// --primary-color-dark: #67bbf4; }
// --primary-color-darker: #cce8fb; }
// --danger-color-lighter: #f3c8c8;
// --danger-color-light: #db5c5a;
// --danger-color: #db5c5a;
// --danger-color-dark: #952220;
// --danger-color-darker: #641715;
// // yes
// --accent-2-color: #063954;
// --accent-2-color-text: #cce8fb;
// }
// }
/* interim */
$font-size: var(--default-font-size);
/* old variables */
$font-color: rgba(255, 255, 255, 1);
$background-color: rgba(40, 44, 48, 1);
$primary-color-lighter: #cce8fb;
$primary-color-light: #67bbf4;
$primary-color: #35a5f1;
$primary-color-dark: #0e80ce;
$primary-color-darker: #095589;
$secondary-color: #9ca8b0;
$secondary-color-dark: #6e7f8a;
$secondary-color-darker: #49545c;
$danger-color-lighter: #f3c8c8;
$danger-color-light: #db5c5a;
$danger-color: #c82e2b;
$danger-color-dark: #952220;
$danger-color-darker: #641715;
$success-color-lighter: #b5f1d5;
$success-color-light: #26d081;
$success-color: #198754;
$success-color-dark: #12653e;
$success-color-darker: #0c4329;
$warning-color-lighter: #fff8e2;
$warning-color-light: #fff6d9;
$warning-color: #fff3cd;
$warning-color-dark: #ffd75a;
$warning-color-darker: #ffc203;
$border-color: #dddddd;
$secondary-background-color: #efefef;
$outline-color: rgba(0, 0, 0, 0.5);
$outline-hover-color: #fff;
$spacer: (
0: 0,
1: 0.5rem,
2: 0.75rem,
3: 1rem,
4: 1.5rem,
5: 3rem,
);

View File

@@ -62,7 +62,7 @@ const props = defineProps({
<style lang="scss"> <style lang="scss">
.attachment-list { .attachment-list {
border: 1px solid $secondary-color; border: 1px solid var(--base-color);
border-collapse: collapse; border-collapse: collapse;
table-layout: fixed; table-layout: fixed;
width: 100%; width: 100%;
@@ -109,11 +109,11 @@ const props = defineProps({
a { a {
display: block; display: block;
color: $secondary-color-dark; color: var(--base-color-dark);
transition: color 0.2s ease-in-out; transition: color 0.2s ease-in-out;
&:hover { &:hover {
color: $primary-color-dark; color: var(--primary-color);
} }
svg { svg {
@@ -127,7 +127,7 @@ const props = defineProps({
.attachment-file-size { .attachment-file-size {
width: 80px; width: 80px;
font-size: 75%; font-size: 75%;
color: $secondary-color-dark; color: var(--base-color-dark);
white-space: nowrap; white-space: nowrap;
text-align: right; text-align: right;
padding-right: 8px; padding-right: 8px;
@@ -143,7 +143,7 @@ const props = defineProps({
.attachment-download a, .attachment-download a,
.attachment-file-size { .attachment-file-size {
padding-left: 0.25rem; padding-left: 8px;
} }
} }
} }

View File

@@ -196,13 +196,14 @@ const handleClickItem = (item: string) => {
<style lang="scss"> <style lang="scss">
.button { .button {
display: inline-block; display: inline-block;
font-family: var(--header-font-family); font-family: var(--button-font-family);
font-weight: 600; font-weight: var(--button-font-weight);
padding: 12px 32px 12px 32px; padding: 12px 32px 12px 32px;
border: 0; border: 0;
background-color: var(--base-color-light); color: var(--button-color-text);
background-color: var(--button-color);
text-decoration: none; text-decoration: none;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); box-shadow: var(--base-shadow);
text-align: center; text-align: center;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
@@ -251,16 +252,16 @@ const handleClickItem = (item: string) => {
margin: 0; margin: 0;
padding: 0; padding: 0;
background-color: inherit; background-color: inherit;
border-color: #999; border-color: var(--button-dropdown-color-border);
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3); box-shadow: var(--base-shadow);
li { li {
margin: 0; margin: 0;
padding: 16px 24px; padding: 16px 24px;
background-color: #fff; background-color: var(--button-dropdown-color);
&:hover { &:hover {
background-color: var(--primary-color-hover); background-color: var(--button-dropdown-color-hover);
} }
} }
} }
@@ -280,7 +281,8 @@ const handleClickItem = (item: string) => {
&:disabled, &:disabled,
&.primary:disabled { &.primary:disabled {
background-color: var(--base-color-dark) !important; color: var(--button-disabled-color-text) !important;
background-color: var(--button-disabled-color) !important;
box-shadow: none; box-shadow: none;
} }
@@ -296,24 +298,19 @@ const handleClickItem = (item: string) => {
font-weight: 600; font-weight: 600;
} }
&.light {
background-color: #eee;
// color: #095589;
color: #333;
}
&.primary { &.primary {
background-color: var(--primary-color); background-color: var(--button-primary-color);
color: var(--base-color); color: var(--button-primary-color-text);
} }
&.secondary { &.secondary {
background-color: #ccc; background-color: var(--button-secondary-color);
color: var(--button-secondary-color-text);
} }
&.danger { &.danger {
background-color: var(--danger-color-light); background-color: var(--button-danger-color);
color: var(--base-color); color: var(--button-danger-color-text);
} }
} }

View File

@@ -8,9 +8,8 @@
<style lang="scss"> <style lang="scss">
.captcha-notice { .captcha-notice {
color: $secondary-color; color: var(base-color-text);
font-size: 65%; font-size: 65%;
line-height: 1.2rem; margin-bottom: 16px;
margin-bottom: map-get($spacer, 4);
} }
</style> </style>

View File

@@ -106,11 +106,11 @@ tinymce.PluginManager.add("gallery", function (editor) {
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
background-color: #fff; background-color: var(--base-color-light);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size: 2rem; font-size: 150%;
color: black; color: black;
padding: .25rem 1.5rem; padding: .25rem 1.5rem;
border-radius: 12px; border-radius: 12px;
@@ -877,20 +877,19 @@ const imageBrowser = (callback, value, meta, gallery = false) => {
padding: 4px 8px; padding: 4px 8px;
font-size: 90%; font-size: 90%;
min-height: auto; min-height: auto;
line-height: normal;
} }
#image-library-search-button { #image-library-search-button {
border-width: 1px 1px 1px 0; border-width: 1px 1px 1px 0;
border-style: solid; border-style: solid;
border-color: #eee; border-color: var(--base-color-border);
border-top-right-radius: 6px; border-top-right-radius: 6px;
border-bottom-right-radius: 6px; border-bottom-right-radius: 6px;
padding: 0 8px; padding: 0 8px;
background-color: #eee; background-color: var(--base-color);
&:hover { &:hover {
background-color: #ddd; background-color: var(--base-color-dark);
} }
} }
} }
@@ -907,12 +906,12 @@ const imageBrowser = (callback, value, meta, gallery = false) => {
button { button {
display: flex; display: flex;
cursor: pointer; cursor: pointer;
background-color: #eee; background-color: var(--base-color);
border-radius: 6px; border-radius: 6px;
padding: 2px; padding: 2px;
&:hover { &:hover {
background-color: #ddd; background-color: var(--base-color-dark);
} }
} }
} }
@@ -960,11 +959,11 @@ const imageBrowser = (callback, value, meta, gallery = false) => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border-radius: 50%; border-radius: 50%;
color: #fff; color: var(--base-color-light);
box-shadow: 0 0 0 2px #fff; box-shadow: 0 0 0 2px #fff;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-color: #0060ce; background-color: var(--primary-color);
} }
.image-gallery-content-item-remove { .image-gallery-content-item-remove {
@@ -979,12 +978,12 @@ const imageBrowser = (callback, value, meta, gallery = false) => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border-radius: 50%; border-radius: 50%;
color: #fff; color: var(--base-color-light);
box-shadow: 0 0 0 2px #fff; box-shadow: var(--base-shadow);
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-size: 50%; background-size: 50%;
background-color: #ce0000; background-color: var(--danger-color);
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" style="fill:white"><path d="M170.5 51.6L151.5 80h145l-19-28.4c-1.5-2.2-4-3.6-6.7-3.6H177.1c-2.7 0-5.2 1.3-6.7 3.6zm147-26.6L354.2 80H368h48 8c13.3 0 24 10.7 24 24s-10.7 24-24 24h-8V432c0 44.2-35.8 80-80 80H112c-44.2 0-80-35.8-80-80V128H24c-13.3 0-24-10.7-24-24S10.7 80 24 80h8H80 93.8l36.7-55.1C140.9 9.4 158.4 0 177.1 0h93.7c18.7 0 36.2 9.4 46.6 24.9zM80 128V432c0 17.7 14.3 32 32 32H336c17.7 0 32-14.3 32-32V128H80zm80 64V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16z" /></svg>'); background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" style="fill:white"><path d="M170.5 51.6L151.5 80h145l-19-28.4c-1.5-2.2-4-3.6-6.7-3.6H177.1c-2.7 0-5.2 1.3-6.7 3.6zm147-26.6L354.2 80H368h48 8c13.3 0 24 10.7 24 24s-10.7 24-24 24h-8V432c0 44.2-35.8 80-80 80H112c-44.2 0-80-35.8-80-80V128H24c-13.3 0-24-10.7-24-24S10.7 80 24 80h8H80 93.8l36.7-55.1C140.9 9.4 158.4 0 177.1 0h93.7c18.7 0 36.2 9.4 46.6 24.9zM80 128V432c0 17.7 14.3 32 32 32H336c17.7 0 32-14.3 32-32V128H80zm80 64V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16z" /></svg>');
} }
@@ -1001,7 +1000,7 @@ const imageBrowser = (callback, value, meta, gallery = false) => {
justify-content: center; justify-content: center;
border-radius: 50%; border-radius: 50%;
color: #fff; color: #fff;
box-shadow: 0 0 0 2px #fff; box-shadow: var(--base-shadow);
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-size: 50%; background-size: 50%;
@@ -1108,7 +1107,6 @@ const imageBrowser = (callback, value, meta, gallery = false) => {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
text-align: center; text-align: center;
line-height: 2rem;
} }
@keyframes spin { @keyframes spin {

View File

@@ -1,10 +1,10 @@
<template> <template>
<form class="SMForm" @submit.prevent="handleSubmit"> <form class="SMForm" @submit.prevent="handleSubmit">
<SMMessage <!-- <SMMessage
v-if="props.modelValue._message.length > 0" v-if="props.modelValue._message.length > 0"
:message="props.modelValue._message" :message="props.modelValue._message"
:type="props.modelValue._messageType" :type="props.modelValue._messageType"
:icon="props.modelValue._messageIcon" /> :icon="props.modelValue._messageIcon" /> -->
<slot></slot> <slot></slot>
</form> </form>
@@ -12,7 +12,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { provide } from "vue"; import { provide } from "vue";
import SMMessage from "./SMMessage.vue";
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {

View File

@@ -133,16 +133,16 @@ handleLoad();
font-size: 300%; font-size: 300%;
margin-bottom: 20px; margin-bottom: 20px;
max-width: 550px; max-width: 550px;
color: #fff; color: var(--hero-color-text);
text-align: left; text-align: left;
text-shadow: 0 0 8px #000; text-shadow: var(--hero-shadow);
} }
p { p {
max-width: 550px; max-width: 550px;
color: #fff; color: var(--hero-color-text);
text-align: left; text-align: left;
text-shadow: 0 0 8px #000; text-shadow: var(--hero-shadow);
} }
} }
@@ -150,10 +150,10 @@ handleLoad();
position: absolute; position: absolute;
bottom: 14px; bottom: 14px;
right: 30px; right: 30px;
color: #ccc; color: var(--hero-caption-color-text);
font-size: 80%; font-size: 80%;
padding: 6px 12px; padding: 6px 12px;
background-color: rgba(0, 0, 0, 0.5); background-color: var(--hero-caption-color);
a { a {
color: inherit; color: inherit;
@@ -162,7 +162,7 @@ handleLoad();
&:hover { &:hover {
text-decoration: none; text-decoration: none;
color: #eee; color: var(--hero-caption-color-link);
} }
} }
} }

View File

@@ -349,7 +349,7 @@ const hideNextArrow = computed(() => {
display: block; display: block;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size: 30px; font-size: 150%;
font-weight: bold; font-weight: bold;
color: white; color: white;
cursor: pointer; cursor: pointer;

View File

@@ -494,20 +494,20 @@ const handleMediaSelect = async () => {
right: 10px; right: 10px;
top: 14px; top: 14px;
color: var(--danger-color); color: var(--danger-color);
font-size: 28px; font-size: 150%;
} }
.clear-icon { .clear-icon {
position: absolute; position: absolute;
right: 12px; right: 12px;
top: 18px; top: 18px;
background-color: #ccc; background-color: var(--input-clear-icon-color);
border-radius: 50%; border-radius: 50%;
font-size: 80%; font-size: 80%;
padding: 1px 1px 1px 0px; padding: 1px 1px 1px 0px;
&:hover { &:hover {
color: #fff; color: var(--input-clear-icon-color-hover);
} }
} }

View File

@@ -143,10 +143,8 @@ handleLoad();
label { label {
position: relative; position: relative;
display: block; display: block;
padding: map-get($spacer, 2) map-get($spacer, 3) map-get($spacer, 0) padding: 8px 16px 0 16px;
map-get($spacer, 3); color: var(--base-color);
line-height: 1.5;
color: $secondary-color-dark;
} }
a.button { a.button {
@@ -156,24 +154,24 @@ handleLoad();
ul { ul {
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
border: 1px solid $border-color; border: 1px solid var(--base-color-border);
li { li {
background-color: #fff; background-color: var(--base-color-light);
display: flex; display: flex;
align-items: center; align-items: center;
padding: map-get($spacer, 2); padding: 16px;
&.attachments-none { &.attachments-none {
justify-content: center; justify-content: center;
ion-icon { ion-icon {
font-size: 1.5rem; font-size: 115%;
} }
p { p {
margin: 0; margin: 0;
padding-left: 0.5rem; padding-left: #{map-get($spacing, 2)};
} }
} }
@@ -189,19 +187,19 @@ handleLoad();
.attachment-media-size { .attachment-media-size {
font-size: 75%; font-size: 75%;
padding-left: 0.75rem; padding-left: #{map-get($spacing, 2)};
color: $secondary-color-dark; color: var(--base-color-dark);
} }
.attachment-media-remove { .attachment-media-remove {
font-size: 1.5rem; font-size: 115%;
padding-top: 0.2rem; padding-top: #{map-get($spacing, 1)};
margin-left: 1rem; margin-left: #{map-get($spacing, 3)};
color: $font-color; color: var(--base-color-text);
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: $danger-color; color: var(--danger-color);
} }
} }
} }

View File

@@ -140,7 +140,6 @@ const tabs = () => {
color: rgba(255, 255, 255, 0.8); color: rgba(255, 255, 255, 0.8);
font-family: var(--header-font-family); font-family: var(--header-font-family);
font-weight: 800; font-weight: 800;
font-size: 18px;
text-decoration: none; text-decoration: none;
padding: 16px 24px; padding: 16px 24px;
white-space: nowrap; white-space: nowrap;
@@ -174,14 +173,4 @@ const tabs = () => {
} }
} }
} }
// @media (prefers-color-scheme: dark) {
// .masthead {
// background-color: var(--primary-color-light);
// .tabs .tab-item.active {
// color: var(--primary-color-light);
// }
// }
// }
</style> </style>

View File

@@ -1,76 +0,0 @@
<template>
<div class="message-container">
<div :class="['message', type]">
<ion-icon v-if="icon" :name="icon"></ion-icon>
<p>{{ message }}</p>
</div>
</div>
</template>
<script setup lang="ts">
defineProps({
message: {
type: String,
default: "",
},
type: {
type: String,
default: "primary",
},
icon: {
type: String,
default: "",
},
});
</script>
<style lang="scss">
.message-container {
justify-content: center;
align-self: center;
.message {
display: flex;
padding: map-get($spacer, 2) map-get($spacer, 3);
margin-bottom: map-get($spacer, 4);
text-align: center;
font-size: 90%;
word-break: break-word;
&.primary {
background-color: $primary-color-lighter;
color: $primary-color-darker;
border: 1px solid $primary-color-lighter;
border-radius: 12px;
}
&.success {
background-color: $success-color-lighter;
color: $success-color-darker;
border: 1px solid $success-color-lighter;
border-radius: 12px;
}
&.error {
background-color: $danger-color-lighter;
color: $danger-color-darker;
border: 1px solid $danger-color-lighter;
border-radius: 12px;
}
ion-icon {
height: 1.3em;
width: 1.3em;
margin-right: map-get($spacer, 1);
}
p {
margin-bottom: 0;
justify-content: center;
align-self: center;
white-space: pre-wrap;
flex: 1;
}
}
}
</style>

View File

@@ -225,10 +225,6 @@ onUnmounted(() => {
gap: 20px; gap: 20px;
} }
.button {
color: #fff;
}
#nav-toggle { #nav-toggle {
padding: 24px; padding: 24px;
cursor: pointer; cursor: pointer;
@@ -276,11 +272,11 @@ onUnmounted(() => {
} }
} }
// @media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
// .navbar #nav-head #nav-toggle { .navbar #nav-head #nav-toggle {
// filter: invert(100%) saturate(0%) brightness(120%); filter: invert(100%) saturate(0%) brightness(120%);
// } }
// } }
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {
#nav-toggle { #nav-toggle {

View File

@@ -117,11 +117,11 @@ if (
align-items: center; align-items: center;
font-size: 30vw; font-size: 30vw;
font-weight: 600; font-weight: 600;
color: #295b7e; color: var(--primary-color);
img { img {
height: 25vw; height: 25vw;
margin: 0 0.5rem 0 1rem; margin: 0 #{map-get($spacing, 2)} 0 #{map-get($spacing, 3)};
} }
} }
@@ -131,7 +131,7 @@ if (
h2 { h2 {
margin-top: 0; margin-top: 0;
margin-bottom: 0.5rem; margin-bottom: #{map-get($spacing, 2)};
} }
} }
} }

View File

@@ -124,25 +124,26 @@ import SMSocialIcons from "../components/SMSocialIcons.vue";
filter: none; filter: none;
} }
ul { .footer-links ul {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
padding: 0; padding: 0;
list-style-type: none; list-style-type: none;
flex-wrap: wrap;
gap: 15px 30px;
justify-content: center;
li { li {
padding: 0; margin: 0;
margin-left: 1rem;
margin-right: 1rem;
margin-bottom: 0;
text-align: center; text-align: center;
white-space: nowrap;
} }
} }
.footer-text { .footer-text {
p { p {
padding: 0; padding: 0;
margin: 0 0 0.5rem 0; margin: 0 0 #{map-get($spacing, 2)} 0;
} }
p:last-of-type { p:last-of-type {
@@ -179,14 +180,14 @@ import SMSocialIcons from "../components/SMSocialIcons.vue";
@media only screen and (max-width: 864px) { @media only screen and (max-width: 864px) {
.footer { .footer {
.footer-text { .footer-text {
padding: 0 1rem; padding: 0 #{map-get($spacing, 3)};
} }
.footer-links ul { .footer-links ul {
flex-direction: column; flex-direction: column;
li { li {
text-align: center; text-align: center;
margin-bottom: 0.5rem; margin-bottom: #{map-get($spacing, 2)};
} }
} }
} }
@@ -198,8 +199,8 @@ import SMSocialIcons from "../components/SMSocialIcons.vue";
margin-top: 0; margin-top: 0;
li { li {
margin-top: 0.25rem; margin-top: #{map-get($spacing, 1)};
margin-bottom: 0.25rem; margin-bottom: #{map-get($spacing, 1)};
} }
} }
} }

View File

@@ -169,9 +169,9 @@ if (props.modelValue < 1 || totalPages < 1) {
.item { .item {
display: flex; display: flex;
cursor: pointer; cursor: pointer;
background-color: var(--base-color-light); background-color: var(--pagination-color);
padding: 12px 16px; padding: 12px 16px;
border-right: 1px solid rgba(0, 0, 0, 0.1); // border-right: 1px solid rgba(0, 0, 0, 0.1);
&.page { &.page {
width: 44px; width: 44px;
@@ -179,7 +179,7 @@ if (props.modelValue < 1 || totalPages < 1) {
} }
&.active { &.active {
background-color: var(--primary-color); background-color: var(--pagination-color-active);
} }
&:first-of-type { &:first-of-type {
@@ -199,13 +199,13 @@ if (props.modelValue < 1 || totalPages < 1) {
} }
&:hover:not(.active):not(.disabled) { &:hover:not(.active):not(.disabled) {
background-color: var(--primary-color-hover); background-color: var(--pagination-color-hover);
} }
&.disabled { &.disabled {
cursor: not-allowed; cursor: not-allowed;
color: var(--base-color-darker); color: var(--pagination-color-disabled-text);
background-color: var(--base-color); background-color: var(--pagination-color-disabled);
} }
} }
} }
@@ -226,10 +226,4 @@ if (props.modelValue < 1 || totalPages < 1) {
} }
} }
} }
// @media (prefers-color-scheme: dark) {
// .pagination .item.active {
// background-color: var(--primary-color-light);
// }
// }
</style> </style>

View File

@@ -19,8 +19,8 @@ const selectedLabel = inject("selectedLabel");
<style lang="scss"> <style lang="scss">
.tab-content { .tab-content {
padding: map-get($spacer, 3); padding: 32px;
background-color: #fff; background-color: var(--tab-color);
border: 1px solid $border-color; border: 1px solid var(--tab-color-border);
} }
</style> </style>

View File

@@ -25,10 +25,9 @@ provide("selectedLabel", selectedLabel);
<style lang="scss"> <style lang="scss">
.tab-group { .tab-group {
margin-bottom: map-get($spacer, 4); margin-bottom: 32px;
.tab-header { .tab-header {
// border-bottom: 1px solid $border-color;
list-style-type: none; list-style-type: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
@@ -36,29 +35,29 @@ provide("selectedLabel", selectedLabel);
.tab-item { .tab-item {
display: inline-block; display: inline-block;
padding: map-get($spacer, 2) map-get($spacer, 3); padding: 16px 24px;
border: 1px solid transparent; border: 1px solid transparent;
margin-bottom: -1px; margin-bottom: -1px;
border-top-left-radius: 8px; border-top-left-radius: 8px;
border-top-right-radius: 8px; border-top-right-radius: 8px;
color: $primary-color; color: var(--primary-color);
transition: 0.2s all ease-out; transition: 0.2s all ease-out;
&.selected { &.selected {
color: $font-color; color: var(--tab-color-text);
background-color: #fff; background-color: var(--tab-color);
border-top: 1px solid $border-color; border-top: 1px solid var(--tab-color-border);
border-left: 1px solid $border-color; border-left: 1px solid var(--tab-color-border);
border-bottom: 1px solid #fff; border-bottom: 1px solid var(--tab-color);
border-right: 1px solid $border-color; border-right: 1px solid var(--tab-color-border);
} }
&:hover:not(.selected) { &:hover:not(.selected) {
color: $primary-color-dark; color: var(--primary-color);
border-top: 1px solid $border-color; border-top: 1px solid var(--tab-color-border);
border-left: 1px solid $border-color; border-left: 1px solid var(--tab-color-border);
border-bottom: 1px solid #fff; border-bottom: 1px solid var(--tab-color);
border-right: 1px solid $border-color; border-right: 1px solid var(--tab-color-border);
} }
} }
} }

View File

@@ -71,7 +71,7 @@ const hasClassLong = (text: unknown): boolean => {
<style lang="scss"> <style lang="scss">
.table { .table {
border: 1px solid #ccc; border: 1px solid var(--table-color-border);
border-collapse: collapse; border-collapse: collapse;
margin-bottom: 32px; margin-bottom: 32px;
width: 100%; width: 100%;
@@ -80,7 +80,7 @@ const hasClassLong = (text: unknown): boolean => {
th { th {
padding: 24px 16px; padding: 24px 16px;
text-align: left; text-align: left;
border-bottom: 1px solid #ccc; border-bottom: 1px solid var(--table-color-border);
} }
th { th {
@@ -90,7 +90,7 @@ const hasClassLong = (text: unknown): boolean => {
td { td {
font-size: 85%; font-size: 85%;
background-color: #fff; background-color: var(--table-color);
&.long { &.long {
font-size: 75%; font-size: 75%;
@@ -101,7 +101,7 @@ const hasClassLong = (text: unknown): boolean => {
tr { tr {
&:hover { &:hover {
td { td {
background-color: var(--primary-color-hover); background-color: var(--table-color-hover);
cursor: pointer; cursor: pointer;
} }
} }
@@ -135,11 +135,11 @@ const hasClassLong = (text: unknown): boolean => {
} }
.table tbody tr { .table tbody tr {
border-bottom: 1px solid #ccc; border-bottom: 1px solid var(--table-color-border);
td { td {
border: none; border: none;
border-bottom: 1px solid #eee; border-bottom: 1px solid var(--table-color-border);
position: relative; position: relative;
padding: 8px 12px 8px 40%; padding: 8px 12px 8px 40%;
white-space: normal; white-space: normal;
@@ -168,7 +168,7 @@ const hasClassLong = (text: unknown): boolean => {
} }
&:nth-child(even) td { &:nth-child(even) td {
background-color: #f8f8f8; background-color: var(--table-color-even);
} }
} }
} }

View File

@@ -104,7 +104,6 @@ onMounted(() => {
p { p {
margin-bottom: 0; margin-bottom: 0;
line-height: 1rem;
word-wrap: break-word; word-wrap: break-word;
} }

View File

@@ -497,8 +497,8 @@ handleLoad();
.media-browser-content { .media-browser-content {
display: flex; display: flex;
height: 40vh; height: 40vh;
border: 1px solid $border-color; border: 1px solid var(--base-color-border);
background-color: #fff; background-color: var(--base-color-light);
justify-content: center; justify-content: center;
align-items: center; align-items: center;
margin: 0 0 16px 0; margin: 0 0 16px 0;
@@ -533,7 +533,7 @@ handleLoad();
&.selected, &.selected,
&:hover { &:hover {
border-color: $primary-color-dark; border-color: var(--primary-color);
} }
.media-image { .media-image {

View File

@@ -5,6 +5,11 @@ import { useApplicationStore } from "../store/ApplicationStore";
import { updateSEOTags } from "../helpers/seo"; import { updateSEOTags } from "../helpers/seo";
export const routes = [ export const routes = [
{
path: "/elements",
name: "elements",
component: () => import("@/views/Elements.vue"),
},
{ {
path: "/", path: "/",
name: "home", name: "home",

View File

@@ -141,7 +141,7 @@ handleLoad();
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {
.page-post-view .heading-image { .page-post-view .heading-image {
height: 10rem; height: #{map-get($spacing, 3) * 10};
} }
} }
</style> </style>

View File

@@ -150,7 +150,8 @@ handleLoad();
.article-card { .article-card {
text-decoration: none; text-decoration: none;
color: var(--base-color-text); color: var(--card-color-text);
margin-bottom: 48px;
&:hover { &:hover {
filter: none; filter: none;
@@ -165,7 +166,7 @@ handleLoad();
border-radius: 7px; border-radius: 7px;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
background-color: var(--card-background-color); background-color: var(--card-color);
box-shadow: var(--base-shadow); box-shadow: var(--base-shadow);
margin-bottom: 24px; margin-bottom: 24px;
} }

View File

@@ -55,7 +55,6 @@ import SMHeader from "../components/SMHeader.vue";
.container-text { .container-text {
max-width: 800px; max-width: 800px;
margin: 0 auto; margin: 0 auto;
line-height: 1.4em;
h3 { h3 {
margin-top: 60px; margin-top: 60px;

View File

@@ -0,0 +1,22 @@
<template>
<SMRow>
<SMColumn style="gap: 15px">
<SMButton label="Button" />
<SMButton type="primary" label="Primary Button" />
<SMButton type="submit" label="Submit Button" />
<SMButton type="secondary" label="Secondary Button" />
<SMButton type="danger" label="Danger Button" />
</SMColumn>
<SMColumn style="gap: 15px">
<SMButton label="Button" disabled />
<SMButton type="primary" label="Primary Button" disabled />
<SMButton type="submit" label="Submit Button" disabled />
<SMButton type="secondary" label="Secondary Button" disabled />
<SMButton type="danger" label="Danger Button" disabled />
</SMColumn>
</SMRow>
</template>
<script setup lang="ts">
import SMButton from "../components/SMButton.vue";
</script>

View File

@@ -6,12 +6,6 @@
backgroundImage: `url('${mediaGetVariantUrl(event.hero)}')`, backgroundImage: `url('${mediaGetVariantUrl(event.hero)}')`,
}"></div> }"></div>
<SMContainer> <SMContainer>
<SMMessage
v-if="formMessage"
icon="alert-circle-outline"
type="error"
:message="formMessage"
class="mt-5" />
<SMContainer class="workshop-page"> <SMContainer class="workshop-page">
<div class="workshop-body"> <div class="workshop-body">
<h2 class="workshop-title">{{ event.title }}</h2> <h2 class="workshop-title">{{ event.title }}</h2>
@@ -117,7 +111,6 @@ import { computed, Ref, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import SMButton from "../components/SMButton.vue"; import SMButton from "../components/SMButton.vue";
import SMHTML from "../components/SMHTML.vue"; import SMHTML from "../components/SMHTML.vue";
import SMMessage from "../components/SMMessage.vue";
import SMAttachments from "../components/SMAttachments.vue"; import SMAttachments from "../components/SMAttachments.vue";
import { api } from "../helpers/api"; import { api } from "../helpers/api";
import { Event, EventResponse } from "../helpers/api.types"; import { Event, EventResponse } from "../helpers/api.types";
@@ -137,11 +130,6 @@ const event: Ref<Event | null> = ref(null);
const route = useRoute(); const route = useRoute();
const pageLoading = ref(true); const pageLoading = ref(true);
/**
* Page message.
*/
const formMessage = ref("");
/** /**
* Page error. * Page error.
*/ */
@@ -256,8 +244,6 @@ const computedAgeNotice = computed(() => {
* Load the page data. * Load the page data.
*/ */
const handleLoad = async () => { const handleLoad = async () => {
formMessage.value = "";
try { try {
let result = await api.get({ let result = await api.get({
url: "/events/{event}", url: "/events/{event}",
@@ -284,13 +270,7 @@ const handleLoad = async () => {
pageError.value = 404; pageError.value = 404;
} }
} catch (error) { } catch (error) {
if (error.status == 404) { pageError.value = error.status;
pageError.value = 404;
} else {
formMessage.value =
error.data?.message ||
"Could not load event information from the server.";
}
} finally { } finally {
pageLoading.value = false; pageLoading.value = false;
} }
@@ -304,17 +284,17 @@ handleLoad();
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
min-height: map-get($spacer, 5) * 4; min-height: 256px;
height: 20vw; height: 20vw;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: cover; background-size: cover;
background-color: #eee; background-color: var(--base-color);
transition: background-image 0.2s; transition: background-image 0.2s;
.workshop-image-loader { .workshop-image-loader {
font-size: 5rem; font-size: 350%;
color: $secondary-color; color: var(--base-color);
} }
} }
@@ -322,85 +302,75 @@ handleLoad();
display: flex; display: flex;
flex-direction: row; flex-direction: row;
.workshop-body,
.workshop-info {
line-height: 1.5rem;
}
.workshop-body { .workshop-body {
flex: 1; flex: 1;
text-align: left; text-align: left;
} }
.workshop-title { .workshop-title {
line-height: 1.15em;
margin-bottom: 32px; margin-bottom: 32px;
} }
.workshop-info { .workshop-info {
width: 18rem; width: 288px;
margin-left: 2rem; margin-left: 32px;
h4 { h4 {
margin-bottom: 0.25rem;
display: flex; display: flex;
align-items: center; align-items: center;
height: 1rem;
.icon { .icon {
display: inline-block; display: inline-block;
width: 1rem; font-size: 20px;
margin-right: 0.5rem; margin-right: 8px;
text-align: center; text-align: center;
} }
} }
p { p {
margin: 0; margin: 0;
padding-left: 1.5rem; padding-left: 28px;
font-size: 90%; font-size: 90%;
} }
.workshop-registration { .workshop-registration {
margin-top: 1.5rem; margin-top: 32px;
line-height: 1.25rem;
} }
.workshop-registration-none, .workshop-registration-none,
.workshop-registration-soon, .workshop-registration-soon,
.workshop-registration-message { .workshop-registration-message {
border: 1px solid #ffeeba; border: 1px solid var(--warning-color-light);
background-color: #fff3cd; background-color: var(--warning-color-lighter);
color: #856404; color: var(--warning-color-dark);
text-align: center; text-align: center;
font-size: 80%; font-size: 80%;
padding: 0.5rem; padding: 8px;
} }
.workshop-registration-closed, .workshop-registration-closed,
.workshop-registration-cancelled { .workshop-registration-cancelled {
border: 1px solid #f5c2c7; border: 1px solid var(--danger-color-light);
background-color: #f8d7da; background-color: var(--danger-color-lighter);
color: #842029; color: var(--danger-color-dark);
text-align: center; text-align: center;
font-size: 80%; font-size: 80%;
padding: 0.5rem; padding: 8px;
} }
.workshop-date, .workshop-date,
.workshop-location, .workshop-location,
.workshop-price, .workshop-price,
.workshop-ages { .workshop-ages {
padding: 0 1rem; padding: 0 16px;
} }
.workshop-ages p { .workshop-ages p {
margin-top: 0.5rem; margin-top: 8px;
margin-left: 1rem; margin-left: 16px;
padding: 0 0 0 0.5rem; padding: 0 0 0 8px;
font-size: 80%; font-size: 80%;
border-left: 4px solid $warning-color; border-left: 4px solid var(--warning-color-darker);
line-height: 1.2rem;
} }
} }
} }

View File

@@ -131,11 +131,11 @@ import SMHero from "../components/SMHero.vue";
h2 { h2 {
font-size: 400%; font-size: 400%;
text-align: center; text-align: center;
color: var(--accent-1-color-text);
} }
p { p {
font-size: 125%; font-size: 125%;
line-height: 150%;
} }
} }
@@ -150,15 +150,14 @@ import SMHero from "../components/SMHero.vue";
p { p {
font-size: 125%; font-size: 125%;
line-height: 150%; max-width: #{calc(map-get($spacing, 6) * 16)};
max-width: 32rem;
margin: 16px auto 32px auto; margin: 16px auto 32px auto;
} }
img { img {
border-radius: 50rem; border-radius: 50%;
height: 360px; height: #{calc(map-get($spacing, 5) * 15)};
width: 360px; width: #{calc(map-get($spacing, 5) * 15)};
} }
.button { .button {
@@ -179,11 +178,11 @@ import SMHero from "../components/SMHero.vue";
h2 { h2 {
font-size: 300%; font-size: 300%;
text-align: center; text-align: center;
color: #f8f8f8;
} }
p { p {
font-size: 125%; font-size: 125%;
line-height: 150%;
text-align: center; text-align: center;
margin: 24px auto; margin: 24px auto;
} }
@@ -231,11 +230,11 @@ import SMHero from "../components/SMHero.vue";
font-size: 300%; font-size: 300%;
text-align: center; text-align: center;
margin-bottom: 16px; margin-bottom: 16px;
color: var(--accent-2-color-text);
} }
p { p {
font-size: 125%; font-size: 125%;
line-height: 1.5em;
} }
.button-row { .button-row {
@@ -280,7 +279,7 @@ import SMHero from "../components/SMHero.vue";
.minecraft-image { .minecraft-image {
float: none; float: none;
display: block; display: block;
margin: 0 auto 1rem auto; margin: 0 auto #{map-get($spacing, 3)} auto;
} }
} }
} }

View File

@@ -106,10 +106,10 @@ const downloads = [
<style lang="scss"> <style lang="scss">
.page-minecraft { .page-minecraft {
h3 { h3 {
margin-bottom: 0.5rem; margin-bottom: #{map-get($spacing, 2)};
} }
li { li {
margin-bottom: 0.5rem; margin-bottom: #{map-get($spacing, 2)};
} }
} }
</style> </style>

View File

@@ -1,95 +1,98 @@
<template> <template>
<SMMastHead title="Workshops" /> <SMPage :error="pageError">
<SMContainer class="flex-grow-1"> <SMMastHead title="Workshops" />
<SMToolbar class="align-items-start"> <SMContainer class="flex-grow-1">
<SMInput <SMToolbar class="align-items-start">
v-model="filterKeywords" <SMInput
label="Keywords" v-model="filterKeywords"
@blur="handleFilter" label="Keywords"
@keyup.enter="handleFilter" /> @blur="handleFilter"
<SMInput @keyup.enter="handleFilter" />
v-model="filterLocation" <SMInput
label="Location" v-model="filterLocation"
@blur="handleFilter" label="Location"
@keyup.enter="handleFilter" /> @blur="handleFilter"
<SMInput @keyup.enter="handleFilter" />
v-model="filterDateRange" <SMInput
type="daterange" v-model="filterDateRange"
label="Date Range" type="daterange"
:feedback-invalid="dateRangeError" label="Date Range"
@blur="handleFilter" :feedback-invalid="dateRangeError"
@keyup.enter="handleFilter" /> @blur="handleFilter"
</SMToolbar> @keyup.enter="handleFilter" />
<SMPagination </SMToolbar>
v-if="postsTotal > postsPerPage" <SMPagination
v-model="postsPage" v-if="postsTotal > postsPerPage"
:total="postsTotal" v-model="postsPage"
:per-page="postsPerPage" /> :total="postsTotal"
<SMMessage :per-page="postsPerPage" />
v-if="formMessage" <SMLoading v-if="pageLoading" large />
icon="alert-circle-outline" <SMNoItems
type="error" v-else-if="events.length == 0"
:message="formMessage" text="No Workshops Found" />
class="mt-5" /> <div v-else class="events">
<router-link
<SMLoading v-if="pageLoading" large /> class="event-card"
<SMNoItems v-else-if="events.length == 0" text="No Workshops Found" /> v-for="event in events"
<div v-else class="events"> :key="event.id"
<router-link :to="{ name: 'event', params: { id: event.id } }">
class="event-card" <div
v-for="event in events" class="thumbnail"
:key="event.id" :style="{
:to="{ name: 'event', params: { id: event.id } }"> backgroundImage: `url('${mediaGetVariantUrl(
<div event.hero,
class="thumbnail" 'medium'
:style="{ )}')`,
backgroundImage: `url('${mediaGetVariantUrl( }">
event.hero, <div :class="['banner', event['bannerType']]">
'medium' {{ event["banner"] }}
)}')`,
}">
<div :class="['banner', event['bannerType']]">
{{ event["banner"] }}
</div>
<div class="date">
<div class="day">
{{ formatDateDay(event.start_at) }}
</div> </div>
<div class="month"> <div class="date">
{{ formatDateMonth(event.start_at) }} <div class="day">
{{ formatDateDay(event.start_at) }}
</div>
<div class="month">
{{ formatDateMonth(event.start_at) }}
</div>
</div> </div>
</div> </div>
</div> <div class="content">
<div class="content"> <h3 class="title">{{ event.title }}</h3>
<h3 class="title">{{ event.title }}</h3> <SMRow class="date" no-responsive>
<SMRow class="date" no-responsive> <ion-icon name="calendar-outline" class="icon" />
<ion-icon name="calendar-outline" class="icon" /> <div class="text">{{ computedDate(event) }}</div>
<div class="text">{{ computedDate(event) }}</div> </SMRow>
</SMRow> <SMRow class="location" no-responsive>
<SMRow class="location" no-responsive> <ion-icon name="location-outline" class="icon" />
<ion-icon name="location-outline" class="icon" /> <div class="text">
<div class="text">{{ computedLocation(event) }}</div> {{ computedLocation(event) }}
</SMRow> </div>
<SMRow class="ages" no-responsive> </SMRow>
<ion-icon name="body-outline" class="icon" /> <SMRow class="ages" no-responsive>
<div class="text">{{ computedAges(event.ages) }}</div> <ion-icon name="body-outline" class="icon" />
</SMRow> <div class="text">
<SMRow class="price" no-responsive> {{ computedAges(event.ages) }}
<div class="icon">$</div> </div>
<div class="text">{{ computedPrice(event.price) }}</div> </SMRow>
</SMRow> <SMRow class="price" no-responsive>
</div> <div class="icon">$</div>
</router-link> <div class="text">
</div> {{ computedPrice(event.price) }}
</SMContainer> </div>
</SMRow>
</div>
</router-link>
</div>
</SMContainer>
</SMPage>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, watch } from "vue"; import { reactive, ref, watch } from "vue";
import SMInput from "../components/SMInput.vue"; import SMInput from "../components/SMInput.vue";
import SMMessage from "../components/SMMessage.vue";
import SMPagination from "../components/SMPagination.vue"; import SMPagination from "../components/SMPagination.vue";
import SMToolbar from "../components/SMToolbar.vue"; import SMToolbar from "../components/SMToolbar.vue";
import SMPage from "../components/SMPage.vue";
import { api } from "../helpers/api"; import { api } from "../helpers/api";
import { Event, EventCollection } from "../helpers/api.types"; import { Event, EventCollection } from "../helpers/api.types";
import { SMDate } from "../helpers/datetime"; import { SMDate } from "../helpers/datetime";
@@ -103,8 +106,6 @@ const pageLoading = ref(true);
let events: Event[] = reactive([]); let events: Event[] = reactive([]);
const dateRangeError = ref(""); const dateRangeError = ref("");
const formMessage = ref("123");
const filterKeywords = ref(""); const filterKeywords = ref("");
const filterLocation = ref(""); const filterLocation = ref("");
const filterDateRange = ref(""); const filterDateRange = ref("");
@@ -112,6 +113,7 @@ const filterDateRange = ref("");
const postsPerPage = 24; const postsPerPage = 24;
let postsPage = ref(1); let postsPage = ref(1);
let postsTotal = ref(0); let postsTotal = ref(0);
const pageError = ref(0);
/** /**
* Load page data. * Load page data.
@@ -170,7 +172,6 @@ const handleLoad = async () => {
} }
pageLoading.value = true; pageLoading.value = true;
formMessage.value = "";
events = []; events = [];
if (query["filter"].length > 0) { if (query["filter"].length > 0) {
@@ -248,11 +249,7 @@ const handleLoad = async () => {
}); });
} }
} catch (error) { } catch (error) {
if (error.status != 404) { pageError.value = error.status;
formMessage.value =
error.response?.data?.message ||
"Could not load any events from the server.";
}
} finally { } finally {
pageLoading.value = false; pageLoading.value = false;
} }

View File

@@ -98,7 +98,7 @@ const courseBoxTitle = computed(() => {
padding: 32px; padding: 32px;
ion-icon { ion-icon {
font-size: 64px; font-size: 350%;
} }
img { img {

View File

@@ -2,8 +2,7 @@
<SMPage :loading="formLoading" permission="logs/discord"> <SMPage :loading="formLoading" permission="logs/discord">
<template #container> <template #container>
<h1>Discord Bot Logs</h1> <h1>Discord Bot Logs</h1>
<SMMessage v-if="message" type="error" :message="message" /> <SMTabGroup>
<SMTabGroup v-if="!message">
<SMTab label="Output"> <SMTab label="Output">
<code v-if="logOutputContent.length > 0">{{ <code v-if="logOutputContent.length > 0">{{
logOutputContent logOutputContent
@@ -15,7 +14,7 @@
}}</code> }}</code>
</SMTab> </SMTab>
</SMTabGroup> </SMTabGroup>
<SMButton v-if="!message" label="Reload Logs" @click="loadData" /> <SMButton label="Reload Logs" @click="loadData" />
</template> </template>
</SMPage> </SMPage>
</template> </template>
@@ -23,20 +22,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from "vue";
import SMButton from "../../components/SMButton.vue"; import SMButton from "../../components/SMButton.vue";
import SMMessage from "../../components/SMMessage.vue";
import SMTab from "../../components/SMTab.vue"; import SMTab from "../../components/SMTab.vue";
import SMTabGroup from "../../components/SMTabGroup.vue"; import SMTabGroup from "../../components/SMTabGroup.vue";
import { api } from "../../helpers/api"; import { api } from "../../helpers/api";
import { LogsDiscordResponse } from "../../helpers/api.types"; import { LogsDiscordResponse } from "../../helpers/api.types";
import { useToastStore } from "../../store/ToastStore";
let formLoading = ref(false); let formLoading = ref(false);
let logOutputContent = ref(""); let logOutputContent = ref("");
let logErrorContent = ref(""); let logErrorContent = ref("");
let message = ref("");
const loadData = async () => { const loadData = async () => {
message.value = "";
try { try {
formLoading.value = true; formLoading.value = true;
const result = await api.get({ url: "/logs/discord" }); const result = await api.get({ url: "/logs/discord" });
@@ -54,7 +50,11 @@ const loadData = async () => {
} }
} }
} catch (error) { } catch (error) {
message.value = "Could not load logs from server"; useToastStore().addToast({
title: "Server Error",
content: "Could not load logs from server",
type: "danger",
});
} finally { } finally {
formLoading.value = false; formLoading.value = false;
} }

View File

@@ -407,8 +407,4 @@ const handleFailValidation = () => {
loadData(); loadData();
</script> </script>
<style lang="scss"> <style lang="scss"></style>
.page-event-edit {
background-color: #f8f8f8;
}
</style>

View File

@@ -325,8 +325,4 @@ loadOptionsAuthors();
loadData(); loadData();
</script> </script>
<style lang="scss"> <style lang="scss"></style>
.page-post-edit {
background-color: #f8f8f8;
}
</style>

View File

@@ -1,7 +1,6 @@
<template> <template>
<SMPage permission="admin/posts" class="page-post-list"> <SMPage permission="admin/posts" :page-error="pageError">
<template #container> <template #container>
<SMMessage v-if="formMessage" type="error" :message="formMessage" />
<SMToolbar> <SMToolbar>
<template #left> <template #left>
<SMButton <SMButton
@@ -63,7 +62,6 @@ import SMDialogConfirm from "../../components/dialogs/SMDialogConfirm.vue";
import SMButton from "../../components/SMButton.vue"; import SMButton from "../../components/SMButton.vue";
import SMInput from "../../components/SMInput.vue"; import SMInput from "../../components/SMInput.vue";
import SMLoadingIcon from "../../components/SMLoadingIcon.vue"; import SMLoadingIcon from "../../components/SMLoadingIcon.vue";
import SMMessage from "../../components/SMMessage.vue";
import SMToolbar from "../../components/SMToolbar.vue"; import SMToolbar from "../../components/SMToolbar.vue";
import { api } from "../../helpers/api"; import { api } from "../../helpers/api";
import { PostCollection, PostResponse } from "../../helpers/api.types"; import { PostCollection, PostResponse } from "../../helpers/api.types";
@@ -83,7 +81,7 @@ const headers = [
]; ];
const items = ref([]); const items = ref([]);
const formMessage = ref(""); const pageError = ref(0);
const formLoading = ref(false); const formLoading = ref(false);
const serverItemsLength = ref(0); const serverItemsLength = ref(0);
@@ -165,7 +163,7 @@ const loadFromServer = async () => {
serverItemsLength.value = data.total; serverItemsLength.value = data.total;
} catch (error) { } catch (error) {
formMessage.value = error.data.message || "An unknown error occurred"; pageError.value = error.status;
} finally { } finally {
formLoading.value = false; formLoading.value = false;
} }
@@ -302,8 +300,4 @@ const handleDelete = async (item) => {
}; };
</script> </script>
<style lang="scss"> <style lang="scss"></style>
.page-post-list {
background-color: #f8f8f8;
}
</style>

View File

@@ -1,15 +1,9 @@
<template> <template>
<SMPage permission="admin/users"> <SMPage permission="admin/users" :page-error="pageError">
<SMMastHead <SMMastHead
title="Users" title="Users"
:back-link="{ name: 'dashboard' }" :back-link="{ name: 'dashboard' }"
back-title="Return to Dashboard" /> back-title="Return to Dashboard" />
<SMMessage
v-if="formMessage.message"
:icon="formMessage.icon"
:type="formMessage.type"
:message="formMessage.message" />
<SMContainer> <SMContainer>
<SMTable <SMTable
:headers="headers" :headers="headers"
@@ -34,14 +28,15 @@ import { reactive, ref, watch } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { openDialog } from "../../components/SMDialog"; import { openDialog } from "../../components/SMDialog";
import DialogConfirm from "../../components/dialogs/SMDialogConfirm.vue"; import DialogConfirm from "../../components/dialogs/SMDialogConfirm.vue";
import SMMessage from "../../components/SMMessage.vue";
import { api } from "../../helpers/api"; import { api } from "../../helpers/api";
import { SMDate } from "../../helpers/datetime"; import { SMDate } from "../../helpers/datetime";
import SMTable from "../../components/SMTable.vue"; import SMTable from "../../components/SMTable.vue";
import SMMastHead from "../../components/SMMastHead.vue"; import SMMastHead from "../../components/SMMastHead.vue";
import { useToastStore } from "../../store/ToastStore";
const router = useRouter(); const router = useRouter();
const searchValue = ref(""); const searchValue = ref("");
const pageError = ref(0);
const headers = [ const headers = [
{ text: "Username", value: "username", sortable: true }, { text: "Username", value: "username", sortable: true },
@@ -55,12 +50,6 @@ const headers = [
]; ];
const items = ref([]); const items = ref([]);
const formMessage = reactive({
icon: "",
type: "",
message: "",
});
const formLoading = ref(false); const formLoading = ref(false);
const serverItemsLength = ref(0); const serverItemsLength = ref(0);
const serverOptions = ref({ const serverOptions = ref({
@@ -76,9 +65,6 @@ const handleRowClick = (item) => {
const loadFromServer = async () => { const loadFromServer = async () => {
formLoading.value = true; formLoading.value = true;
formMessage.type = "error";
formMessage.icon = "alert-circle-outline";
formMessage.message = "";
try { try {
let params = {}; let params = {};
@@ -163,10 +149,17 @@ const handleDelete = async (user) => {
await api.delete(`users${user.id}`); await api.delete(`users${user.id}`);
loadFromServer(); loadFromServer();
formMessage.message = "User deleted successfully"; useToastStore().addToast({
formMessage.type = "success"; title: "User Deleted",
content: "User deleted successfully.",
type: "success",
});
} catch (err) { } catch (err) {
formMessage.message = err.response?.data?.message; useToastStore().addToast({
title: "Server Error",
content: "User could not be deleted because an error occurred.",
type: "danger",
});
} }
} }
}; };