fix: visual bugs (#934)

This commit is contained in:
saintnoodle
2023-08-17 19:17:16 +01:00
committed by GitHub
parent e25c4484da
commit bfbcd199af
57 changed files with 566 additions and 2425 deletions
-928
View File
@@ -1,928 +0,0 @@
$black: #000000 !default;
$white: #ffffff !default;
$gray-100: #f3f6f9 !default;
$gray-200: #ebedf3 !default;
$gray-300: #e4e6ef !default;
$gray-400: #d1d3e0 !default;
$gray-500: #b5b5c3 !default;
$gray-600: #7e8299 !default;
$gray-700: #5e6278 !default;
$gray-800: #3f4254 !default;
$gray-900: #181c32 !default;
// THESE ARE INVERTED BECAUSE THAT'S HOW WE NEED IT
$dark: $gray-200 !default;
$dark-75: $gray-300 !default;
$dark-65: $gray-400 !default;
$dark-50: $gray-500 !default;
$dark-25: $gray-600 !default;
$text-muted: $gray-500 !default;
$grays: (
"100": $gray-100,
"200": $gray-200,
"300": $gray-300,
"400": $gray-400,
"500": $gray-500,
"600": $gray-600,
"700": $gray-700,
"800": $gray-800,
"900": $gray-900,
) !default;
// Bootstrap standard & extended colors
// Dark colors
$dark: $dark !default;
$dark-hover: darken($dark, 3%) !default;
$dark-light: $gray-400 !default;
$dark-inverse: $white !default;
// Primary colors
$primary: #3699ff !default;
$primary-hover: #187de4 !default;
$primary-light: #e1f0ff !default;
$primary-inverse: $white !default;
// Secondary colors
$secondary: $gray-300 !default;
$secondary-hover: darken($gray-300, 4%) !default;
$secondary-light: $gray-200 !default;
$secondary-inverse: $dark-75 !default;
// Success colors
$success: #1bc5bd !default;
$success-hover: #0bb7af !default;
$success-light: #c9f7f5 !default;
$success-inverse: $white !default;
// Inco colors
$info: #8950fc !default;
$info-hover: #7337ee !default;
$info-light: #eee5ff !default;
$info-inverse: $white !default;
// Warning colors
$warning: #ffa800 !default;
$warning-hover: #ee9d01 !default;
$warning-light: #fff4de !default;
$warning-inverse: $white !default;
// Danger colors
$danger: #f64e60 !default;
$danger-hover: #ee2d41 !default;
$danger-light: #ffe2e5 !default;
$danger-inverse: $white !default;
// Light colors
$light: $gray-100 !default;
$light-hover: $gray-300 !default;
$light-light: $gray-100 !default;
$light-inverse: $gray-600 !default;
// White colors
$white: $white !default;
$white-hover: $gray-100 !default;
$white-light: $white !default;
$white-inverse: $dark-75 !default;
// Bootstrap theme colors
$theme-colors: (
"white": $white,
// custom color type
"primary": $primary,
"secondary": $secondary,
"success": $success,
"info": $info,
"warning": $warning,
"danger": $danger,
"light": $light,
"dark": $dark,
) !default;
// Extended hover colors for Bootstrap theme colors
$theme-hover-colors: (
"white": $white-hover,
// custom color type
"primary": $primary-hover,
"secondary": $secondary-hover,
"success": $success-hover,
"info": $info-hover,
"warning": $warning-hover,
"danger": $danger-hover,
"light": $light-hover,
"dark": $dark-hover,
) !default;
// Extended inverse colors for Bootstrap theme colors
$theme-inverse-colors: (
"white": $white-inverse,
"primary": $primary-inverse,
"secondary": $secondary-inverse,
"success": $success-inverse,
"info": $info-inverse,
"warning": $warning-inverse,
"danger": $danger-inverse,
"light": $light-inverse,
"dark": $dark-inverse,
) !default;
// Extended outline colors for Bootstrap theme colors
$theme-outline-inverse-colors: (
"white": $white,
"primary": $primary,
"secondary": $dark-75,
"success": $success,
"info": $info,
"warning": $warning,
"danger": $danger,
"light": $dark-75,
"dark": $dark,
) !default;
// Extended light colors for Bootstrap theme colors
$theme-light-colors: (
"white": $white-light,
"primary": $primary-light,
"secondary": $secondary-light,
"success": $success-light,
"info": $info-light,
"warning": $warning-light,
"danger": $danger-light,
"light": $light-light,
"dark": $dark-light,
) !default;
// Extended shadow colors for Bootstrap theme colors
$theme-shadow-colors: (
"white": $dark,
"primary": $primary,
"secondary": $dark,
"success": $success,
"info": $info,
"warning": $warning,
"danger": $danger,
"light": $dark,
"dark": $dark,
) !default;
// Extended theme text colors
$theme-text-colors: (
"white": $white,
"primary": $primary,
"secondary": $dark,
"success": $success,
"info": $info,
"warning": $warning,
"danger": $danger,
"light": $light,
"dark": $dark,
"dark-75": $dark-75,
"dark-65": $dark-65,
"dark-50": $dark-50,
"dark-25": $dark-25,
"muted": $text-muted,
) !default;
// Social Network Colors Used With Bootstrap Buttons(see: https://primarycolors.net/)
$social-colors: (
facebook: (
base: #3b5998,
inverse: #ffffff,
light: rgba(#3b5998, 0.1),
hover: darken(#3b5998, 7.5%),
),
google: (
base: #dd4b39,
inverse: #ffffff,
light: rgba(#dd4b39, 0.1),
hover: darken(#dd4b39, 7.5%),
),
twitter: (
base: #1da1f2,
inverse: #ffffff,
light: rgba(#1da1f2, 0.1),
hover: darken(#1da1f2, 7.5%),
),
instagram: (
base: #e1306c,
inverse: #ffffff,
light: rgba(#e1306c, 0.1),
hover: darken(#e1306c, 7.5%),
),
youtube: (
base: #ff0000,
inverse: #ffffff,
light: rgba(#ff0000, 0.1),
hover: darken(#ff0000, 7.5%),
),
linkedin: (
base: #0077b5,
inverse: #ffffff,
light: rgba(#0077b5, 0.1),
hover: darken(#0077b5, 7.5%),
),
skype: (
base: #00aff0,
inverse: #ffffff,
light: rgba(#00aff0, 0.1),
hover: darken(#00aff0, 7.5%),
),
) !default;
// Extended custom spacing for Bootstrap
//
// Control the default styling of most Bootstrap elements by modifying these
// variables. Mostly focused on spacing.
// You can add more entries to the $spacers map, should you need more variation.
$spacer: 1rem !default;
// stylelint-disable-next-line scss/dollar-variable-default
$spacers: (
0: 0,
1: (
$spacer * 0.25,
),
// 3.5px
2:
(
$spacer * 0.5,
),
// 7px;
3:
(
$spacer * 0.75,
),
// 10.5px
4:
(
$spacer * 1,
),
// 14px
5:
(
$spacer * 1.25,
),
// 17.5px
6:
(
$spacer * 1.5,
),
// 21px
7:
(
$spacer * 1.75,
),
// 24.5px
8:
(
$spacer * 2,
),
// 28px
9:
(
$spacer * 2.25,
),
// 31.5px
10:
(
$spacer * 2.5,
),
// 35px
11:
(
$spacer * 2.75,
),
// 38.5px
12:
(
$spacer * 3,
),
// 42px
13:
(
$spacer * 3.25,
),
// 45.5px
14:
(
$spacer * 3.5,
),
// 49px
15:
(
$spacer * 3.75,
),
// 52.5px
16:
(
$spacer * 4,
),
// 55px
17:
(
$spacer * 4.25,
),
// 58.5px
18:
(
$spacer * 4.5,
),
// 62px
19:
(
$spacer * 4.75,
),
// 65.5px
20:
(
$spacer * 5,
),
// 69px
21:
(
$spacer * 5.25,
),
// 73.5px
22:
(
$spacer * 5.5,
),
// 77px
23:
(
$spacer * 5.75,
),
// 80.5px
24:
(
$spacer * 6,
),
// 84px
25:
(
$spacer * 6.25,
),
// 87.5px
26:
(
$spacer * 6.5,
),
// 91px
27:
(
$spacer * 6.75,
),
// 94.5px
28:
(
$spacer * 7,
),
// 99px
29:
(
$spacer * 7.25,
),
// 102.5px
30:
(
$spacer * 7.5,
),
// 106px
31:
(
$spacer * 7.75,
),
// 109.5px
32:
(
$spacer * 8,
),
// 113px
33:
(
$spacer * 8.25,
),
// 116.5px
34:
(
$spacer * 8.5,
),
// 120px
35:
(
$spacer * 8.75,
),
// 123.5px
36:
(
$spacer * 9,
),
// 127px
37:
(
$spacer * 9.25,
),
// 130.5px
48:
(
$spacer * 9.5,
),
// 134px
39:
(
$spacer * 9.75,
),
// 137.5px
40:
(
$spacer * 10,
),
// 140px
);
// Components
//
// Define common padding and border radius sizes and more.
$line-height-xl: 1.8 !default;
$line-height-lg: 1.5 !default;
$line-height-sm: 1.35 !default;
$component-light-style-opacity: 0.1 !default;
$component-active-color: $white !default;
$component-active-bg: $primary !default;
// Box shadow
$box-shadow-xs: 0 0.25rem 0.5rem 0 rgba($black, 0.05);
$box-shadow-sm: 0 0.1rem 1rem 0.25rem rgba($black, 0.05) !default;
$box-shadow: 0 0.5rem 1.5rem 0.5rem rgba($black, 0.075) !default;
$box-shadow-lg: 0 1rem 2rem 1rem rgba($black, 0.1) !default;
// Border Radiues
$border-radius-sm: 0.28rem !default;
$border-radius: 0.42rem !default;
$border-radius-lg: 0.85rem !default;
$border-radius-xl: 1.25rem !default;
// Border settings
$border-color: $gray-200 !default;
$border-width: 1px !default;
// Hover background color
$hover-bg: $gray-100 !default;
// Activebackground color
$active-bg: darken($gray-100, 1%) !default;
// Options
//
// Quickly modify global styling by enabling or disabling optional features.
$enable-rounded: true !default;
$enable-shadows: true !default;
// Grid breakpoints
//
// Define the minimum dimensions at which your layout will change,
// adapting to different screen sizes, for use in media queries.
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px // custom breakpoint,,
) !default;
// Grid containers
//
// Define the maximum width of `.container` for different screen sizes.
$container-max-widths: (
sm: 540px,
md: 720px,
lg: 960px,
xl: 1140px,
xxl: 1340px,
) !default;
// Grid columns
//
// Set the number of columns and specify the width of the gutters.
$grid-columns: 12 !default;
$grid-gutter-width: 25px !default;
$grid-divider-bg: $gray-200 !default;
// Body
// Settings for the `<body>` element.
$body-bg: $tachi-backestground !default;
$body-color: $gray-200 !default;
// Typography
//
// Font, line-height, and color for body text, headings, and more.
// Font family
$font-family-base: Poppins, Helvetica, "sans-serif" !default;
$font-size-base: 1rem !default; // Assumes the browser default, typically `13px`
$font-size-lg: $font-size-base * 1.08 !default; // 14.04px
$font-size-sm: $font-size-base * 0.925 !default; // 12.025px
$font-size-xs: $font-size-base * 0.8 !default; // 10.4px
$h1-font-size: $font-size-base * 2 !default; // 26px
$h2-font-size: $font-size-base * 1.75 !default; // 22.75px
$h3-font-size: $font-size-base * 1.5 !default; // 19.5px
$h4-font-size: $font-size-base * 1.35 !default; // 17.55px
$h5-font-size: $font-size-base * 1.25 !default; // 16.25px
$h6-font-size: $font-size-base * 1.175 !default; // 15.275px
$headings-margin-bottom: $spacer / 2 !default;
$headings-font-family: null !default;
$headings-font-weight: 500 !default;
$headings-line-height: 1.2 !default;
$headings-color: null !default;
$display1-size: 5.5rem !default; // 71.5px
$display2-size: 4.5rem !default; // 58.5px
$display3-size: 3.5rem !default; // 45.5px
$display4-size: 2.5rem !default; // 32.5px
$display5-size: 2.25rem !default; // 29.5px
// Font Sizes
$font-sizes: (
font-size-h1: $h1-font-size,
font-size-h2: $h2-font-size,
font-size-h3: $h3-font-size,
font-size-h4: $h4-font-size,
font-size-h5: $h5-font-size,
font-size-h6: $h6-font-size,
display1: $display1-size,
display2: $display2-size,
display3: $display3-size,
display4: $display4-size,
display5: $display5-size,
) !default;
$display1-weight: 300 !default;
$display2-weight: 300 !default;
$display3-weight: 300 !default;
$display4-weight: 300 !default;
$display-line-height: $headings-line-height !default;
$lead-font-size: $font-size-base * 1.25 !default;
$lead-font-weight: 300 !default;
$small-font-size: 80% !default;
// Font Weight
$font-weight-lighter: lighter !default;
$font-weight-light: 300 !default;
$font-weight-normal: 400 !default;
$font-weight-bold: 500 !default;
$font-weight-bolder: 600 !default;
$font-weight-boldest: 700 !default;
$line-height-base: 1.5 !default;
// Transition
$transition: all 0.15s ease !default;
$transition-link: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease !default;
$transition-input: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease !default;
// Links
//
// Style anchor elements.
$link-color: $primary !default;
$link-decoration: none !default;
$link-hover-color: darken($primary, 15%) !default;
$link-hover-decoration: underline !default;
// Darken percentage for links with `.text-*` class (e.g. `.text-success`)
$emphasized-link-hover-darken-percentage: 15% !default;
// Buttons + Forms
//
// Shared variables that are reassigned to `$input-` and `$btn-` specific variables.
$input-btn-padding-y: 0.65rem !default;
$input-btn-padding-x: 1rem !default;
$input-btn-font-family: null !default;
$input-btn-font-size: $font-size-base !default;
$input-btn-line-height: $line-height-base !default;
$input-btn-focus-width: 0.2rem !default;
$input-btn-focus-color: rgba($component-active-bg, 0.25) !default;
$input-btn-focus-box-shadow: none !default;
$input-btn-padding-y-sm: 0.55rem !default;
$input-btn-padding-x-sm: 0.75rem !default;
$input-btn-font-size-sm: $font-size-sm !default;
$input-btn-line-height-sm: $line-height-sm !default;
$input-btn-padding-y-lg: 0.825rem !default;
$input-btn-padding-x-lg: 1.42rem !default;
$input-btn-font-size-lg: $font-size-lg !default;
$input-btn-line-height-lg: $line-height-lg !default;
$input-btn-border-width: $border-width !default;
// Buttons
//
// For each of Bootstrap's buttons, define text, background, and border color.
$btn-disabled-opacity: 0.6 !default;
$btn-transition: color 0.3s ease-in-out, background-color 0.3s ease-in-out, border-color 0.3s ease-in-out,
box-shadow 0.3s ease-in-out !default;
$btn-box-shadow: none !default;
$btn-focus-box-shadow: none !default;
$btn-active-box-shadow: none !default;
$btn-font-weight: normal !default;
$btn-secondary-color: $tachi-lightground !default;
$btn-secondary-hover-bg-color: $tachi-background !default;
$btn-icon-size-xs: 24px !default; //custom parameter
// Allows for customizing button radius independently from global border radius
$btn-border-radius: $border-radius !default;
$btn-border-radius-lg: $border-radius !default;
$btn-border-radius-sm: $border-radius !default;
$input-plaintext-color: $dark-75 !default;
$input-placeholder-color: $text-muted !default;
$input-color: $dark-75 !default;
$input-border-color: $gray-300 !default;
$input-border-width: $input-btn-border-width !default;
$input-box-shadow: none !default;
$input-focus-border-color: lighten($primary, 10%);
$input-focus-box-shadow: none !default;
$input-height-border: $input-border-width * 2 !default;
$input-bg: $white !default;
$input-disabled-bg: $gray-100 !default;
$input-readonly-bg: $white !default;
$input-group-icon-color: $dark-75 !default;
$input-group-addon-color: $dark-75 !default;
$input-group-addon-bg: $gray-100 !default;
$input-border-radius: $border-radius !default;
$input-border-radius-lg: $border-radius !default;
$input-border-radius-sm: $border-radius-sm !default;
$input-solid-bg: $gray-100;
$input-solid-bg-focus: $gray-200;
$input-solid-placeholder-color: $input-placeholder-color;
$input-solid-color: $dark-75;
$custom-control-indicator-checked-box-shadow: none !default;
$custom-control-indicator-active-box-shadow: none !default;
// Forms
$form-group-margin-bottom: 1.75rem !default;
$form-label-font-size: 1rem !default;
$form-label-font-weight: 400 !default;
$form-feedback-font-size: 0.9rem !default;
$form-feedback-font-weight: 400 !default;
$form-text-font-size: 0.9rem !default;
$form-text-font-weight: 400 !default;
$form-validation-input-shadow: false;
// Table
$table-bg: $tachi-background !default;
$table-accent-bg: #1c1c1c !default;
$table-hover-bg: #7e7678 !default;
$table-active-bg: $table-hover-bg !default;
$table-border-color: #383f45 !default;
$table-head-bg: $gray-100 !default;
$table-head-color: $dark-75 !default;
$table-head-font-size: 1rem !default;
$table-head-font-weight: 600 !default;
$table-dark-color: $white !default;
$table-dark-bg: $dark !default;
$table-dark-accent-bg: rgba($white, 0.05) !default;
$table-dark-hover-color: $table-dark-color !default;
$table-dark-hover-bg: rgba($white, 0.075) !default;
$table-dark-border-color: lighten($table-dark-bg, 7.5%) !default;
$table-head-bg: $gray-100 !default;
$table-compact-head-font-size: 0.9rem !default;
$table-compact-head-color: $text-muted !default;
$table-compact-head-text-transform: uppercase !default;
$table-compact-head-font-weight: 600 !default;
$table-compact-head-font-weight: 600 !default;
$table-compact-head-letter-spacing: 0.1rem !default;
// Card
$card-box-shadow: 0px 0px 30px 0px rgba(82, 63, 105, 0.05) !default; // card custom shadow
$card-border-color: $black !default;
$card-cap-bg: $white !default;
$card-spacer-y: 2rem !default;
$card-spacer-x: 2.25rem !default;
$card-border-radius: $border-radius !default;
$card-header-spacer-y: 1rem !default;
$card-header-height: 70px !default;
$card-sticky-header-bg: $tachi-lightground !default;
$card-sticky-header-height: 70px !default;
$card-sticky-zindex: 101 !default;
$card-sticky-shadow: 0px 1px 15px 1px rgba(69, 65, 78, 0.1) !default;
// List group
$list-group-border-color: $gray-200 !default;
$list-group-hover-bg: $gray-200 !default;
// Modals
// Padding applied to the modal body
$modal-inner-padding: 1.75rem !default;
// Margin between elements in footer, must be lower than or equal to 2 * $modal-inner-padding
$modal-footer-margin-between: 0.5rem !default;
$modal-dialog-margin: 0.5rem !default;
$modal-dialog-margin-y-sm-up: 1.75rem !default;
$modal-content-color: null !default;
$modal-content-bg: $white !default;
$modal-content-border-color: rgba($black, 0.2) !default;
$modal-content-border-width: 0 !default;
$modal-content-border-radius: $border-radius !default;
$modal-content-inner-border-radius: $border-radius !default;
$modal-content-box-shadow: 0 0.25rem 0.5rem rgba($black, 0.05) !default;
$modal-content-box-shadow-xs: 0 0.25rem 0.5rem rgba($black, 0.1) !default;
$modal-content-box-shadow-sm-up: 0 0.5rem 1rem rgba($black, 0.1) !default;
$zindex-modal: 1050 !default;
$modal-backdrop-bg: $black !default;
$modal-backdrop-opacity: 0.6 !default;
$modal-header-border-color: $border-color !default;
$modal-footer-border-color: $border-color !default;
$modal-header-border-width: 1px !default;
$modal-footer-border-width: 1px !default;
$modal-header-padding-y: 1.5rem !default;
$modal-header-padding-x: 1.75rem !default;
$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility
$modal-xl: 1140px !default;
$modal-lg: 800px !default;
$modal-md: 500px !default;
$modal-sm: 300px !default;
// Pagination
$pagination-color: $primary !default;
$pagination-border-color: $gray-300 !default;
$pagination-hover-bg: $gray-200 !default;
$pagination-hover-border-color: $gray-300 !default;
$pagination-disabled-border-color: $gray-200 !default;
// Dropdowns
// Dropdown menu container and contents.
$dropdown-box-shadow: 0px 0px 50px 0px rgba(82, 63, 105, 0.15) !default;
$zindex-dropdown: 96 !default;
$dropdown-border-radius: $border-radius !default;
$dropdown-border-width: 0 !default;
$dropdown-item-padding-y: 0.75rem !default;
$dropdown-item-padding-x: 1.25rem !default;
$dropdown-divider-bg: $gray-200 !default;
$dropdown-menu-widths: (
sm: 175px,
md: 250px,
lg: 350px,
xl: 400px,
xxl: 600px,
);
// Popovers
$popover-font-size: 0.9rem !default;
$popover-max-width: 276px !default;
$popover-border-width: 1px !default;
$popover-border-color: #ffffff !default;
$popover-border-radius: $border-radius !default;
$popover-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.15) !default;
$popover-header-bg: #ffffff !default;
$popover-header-color: $dark !default;
$popover-header-font-weight: 500 !default;
$popover-header-font-size: 1rem !default;
$popover-header-padding-y: 1rem !default;
$popover-header-padding-x: 1.25rem !default;
$popover-header-border-color: $black !default;
$popover-body-color: $body-color !default;
// Tooltips
$tooltip-font-size: 0.9rem !default;
$tooltip-max-width: 200px !default;
$tooltip-color: $dark-75 !default;
$tooltip-bg: #ffffff !default;
$tooltip-border-radius: 3px !default;
$tooltip-opacity: 1 !default;
$tooltip-box-shadow: $popover-box-shadow !default;
$tooltip-padding-y: 0.75rem !default;
$tooltip-padding-x: 1rem !default;
$tooltip-margin: 0 !default;
// Custom Toasts
$toast-zindex: $zindex-dropdown + 100 !default;
$toast-spacing: 2rem !default;
$toast-width: 350px !default;
$toast-box-shadow: $dropdown-box-shadow !default;
$toast-header-color: $dark-75 !default;
$toast-header-background-color: $tachi-lightground !default;
$toast-header-border-color: $gray-200 !default;
// Progress bars
$progress-height: 1rem !default;
$progress-height-xs: 0.5rem !default;
$progress-height-sm: 0.75rem !default;
$progress-height-lg: 1.5rem !default;
$progress-bg: $gray-200 !default;
$progress-border-radius: $border-radius !default;
$progress-box-shadow: none !default;
$progress-bar-color: $white !default;
$progress-bar-bg: $primary !default;
$progress-bar-animation-timing: 1s linear infinite !default;
$progress-bar-transition: width 0.6s ease !default;
// Badges
$badge-padding-y: 0.5em !default;
$badge-padding-x: 0.75em !default;
$badge-font-size: 85% !default;
// Code
$code-bg: #101010 !default;
$code-padding: 0.15rem 0.5rem !default;
// Modals
// Padding applied to the modal body
$modal-inner-padding: 1rem !default;
$modal-dialog-margin: 0.5rem !default;
$modal-dialog-margin-y-sm-up: 1.75rem !default;
$modal-title-color: $dark !default;
$modal-title-font-weight: 500 !default;
$modal-title-font-size: 1.3rem !default;
$modal-title-small-color: $text-muted !default;
$modal-title-small-font-weight: 400 !default;
$modal-title-small-font-size: 0.9rem !default;
$modal-title-close-font-size: 1rem !default;
$modal-title-close-color: $text-muted !default;
$modal-title-close-hover-color: $primary !default;
$modal-content-color: null !default;
$modal-content-bg: $white !default;
$modal-content-border-color: rgba($black, 0.2) !default;
$modal-content-border-radius: $border-radius-lg !default;
$modal-content-box-shadow-xs: 0 0.25rem 0.5rem rgba($black, 0.5) !default;
$modal-content-box-shadow-sm-up: 0 0.5rem 1rem rgba($black, 0.5) !default;
$modal-backdrop-bg: $black !default;
$modal-backdrop-opacity: 0.5 !default;
$modal-header-border-color: $border-color !default;
$modal-footer-border-color: $modal-header-border-color !default;
$modal-xl: 1140px !default;
$modal-lg: 800px !default;
$modal-md: 500px !default;
$modal-sm: 300px !default;
// Pagination
$pagination-padding-y: 0.5rem !default;
$pagination-padding-x: 0.75rem !default;
$pagination-padding-y-sm: 0.25rem !default;
$pagination-padding-x-sm: 0.5rem !default;
$pagination-padding-y-lg: 0.75rem !default;
$pagination-padding-x-lg: 1.5rem !default;
$pagination-line-height: 1.25 !default;
$pagination-color: $link-color !default;
$pagination-bg: $white !default;
$pagination-border-color: $gray-300 !default;
$pagination-focus-box-shadow: none !default;
$pagination-focus-outline: 0 !default;
$pagination-hover-color: $link-hover-color !default;
$pagination-hover-bg: $gray-200 !default;
$pagination-hover-border-color: $gray-300 !default;
$pagination-disabled-color: $gray-600 !default;
$pagination-disabled-bg: $white !default;
$pagination-disabled-border-color: $gray-300 !default;
// Alerts
//
// Define alert colors, border radius, and padding.
$alert-box-shadow: $card-box-shadow !default;
// Navs
$nav-link-px: 1.5rem;
$nav-link-py: 0.75rem;
$nav-btn-px: 1rem;
$nav-section-py: 0.5rem;
$nav-elem-space: 0.25rem;
$nav-link-bg-hover: $gray-100;
$nav-link-bg-active: $gray-200;
$nav-header-py: 1rem;
$nav-footer-py: 1rem;
$nav-font-size: 1rem;
$nav-icon-size: 1.25rem;
$nav-icon-width: 2rem;
-12
View File
@@ -1,12 +0,0 @@
// Theme colors
$primary: $tachi-primary;
$primary-hover: $tachi-primary-hover;
$primary-light: #e888af;
$secondary: #605a5c;
$secondary-hover: #7e7678;
$secondary-light: #c3b9bb;
$info: $tachi-info;
$info-hover: $tachi-info-hover;
$info-light: #A4B9D2;
-158
View File
@@ -1,158 +0,0 @@
// Bootstrap
@import "bootstrap-scss/_mixins.scss";
@import "variables.demo";
@import "variables.bootstrap";
.example-highlight > pre {
background: none transparent !important;
margin: 0 !important;
padding-top: 0.5rem;
code {
overflow-y: auto;
display: block;
span {
background: none transparent !important;
}
}
}
.json > pre {
background: none #fff !important;
}
.example-code > .json {
background: none #fff !important;
}
.symbol.symbol-45 > svg {
width: 100%;
max-width: 45px;
height: 45px;
}
.react-bootstrap-table {
overflow-x: auto;
}
.react-bootstrap-table {
th {
outline: none;
&.sortable {
.svg-icon-sort {
opacity: 0;
}
&:hover {
cursor: pointer;
.svg-icon-sort {
opacity: 1;
}
}
}
}
.table.table-head-custom thead tr {
.sortable-active {
color: #6993ff !important;
}
}
}
.cursor-default {
cursor: default !important;
}
.display-block {
display: block;
}
.d-grid{
display: grid;
}
.fading-image-td-left {
position: relative;
z-index: 1;
&:before {
content: "";
display: block;
background-image: var(--image-url);
mask-image: linear-gradient(to left, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2) 30%, rgba(0, 0, 0, 0));
-webkit-mask-image: linear-gradient(to left, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2) 30%, rgba(0, 0, 0, 0));
background-size: cover;
background-repeat: no-repeat;
background-position: inherit;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
}
}
.fading-image-td-right {
position: relative;
z-index: 1;
&:before {
content: '';
display: block;
background-image: var(--image-url);
mask-image: linear-gradient(to right, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0));
-webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0));
background-size: cover;
background-repeat: no-repeat;
background-position: inherit;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
}
}
.quest-anchor {
scroll-margin-top: 100px;
}
.tooltip-max > .tooltip-inner {
width: 100%;
max-width: unset !important;
}
@include media-breakpoint-up(lg) {
.MuiTabs-flexContainer {
width: 100%;
justify-content: space-around
}
}
.topbar {
justify-content: end;
}
@include media-breakpoint-up(lg) {
.session-raise-container {
width: 100%;
display: flex;
}
}
@include media-breakpoint-down(md) {
.session-raise-container {
width: 100%;
display: flex;
flex-direction: column;
}
}
.MuiTabs-scrollButtons.Mui-disabled {
opacity: 0.3;
}
@import "tachi-custom/custom", "tachi-custom/hero", "tachi-custom/splash-screen";
-7
View File
@@ -1,7 +0,0 @@
// This is an empty scss file.
// You might wonder why we import it.
// Well, our "entry point" to our scss is dynamic
// and depends on additionalData (see vite.config.js).
// However, the SCSS loader will not bother with that additionalData
// if it finds no SCSS files to load. This 'empty' file actually
// determines whether we render any CSS at all. Fun!
-178
View File
@@ -1,178 +0,0 @@
.card-nav-icon {
color: #999;
transition: 100ms;
&:hover {
color: $tachi-primary !important;
}
}
.stat-overview-card {
box-shadow: black 0px 0px 2px 1px !important;
}
.card-dark {
background-color: #1c1c1c !important;
> .card-header {
background-color: #1c1c1c !important;
}
> .card-footer {
background-color: #1c1c1c !important;
}
}
.fake-row {
td {
padding: 0 !important;
border-top: none;
}
}
.tr-dropdown-container {
padding: 4px;
border-top: 1px solid $table-border-color;
background-color: $tachi-background;
&.collapsing {
border-bottom: 1px solid $table-border-color;
}
}
.gentle-link {
color: white;
&:hover {
color: $tachi-primary;
}
}
@include media-breakpoint-down(sm) {
#kt_content {
padding-top: 55px;
}
.background-image {
top: 55px;
}
}
@include media-breakpoint-up(md) {
#kt_content {
padding-top: 80px;
}
.background-image {
top: 80px;
}
}
.highlighted-row {
td {
background-color: rgba($color: $tachi-primary, $alpha: 0.1);
}
}
.nav-link {
&:hover {
background-color: unset !important;
}
}
.text-monospace {
font-family: monospace;
}
.modal {
.form-control {
background-color: $tachi-overground;
}
}
.ladder-header {
background-color: #2b292b;
font-size: x-large;
vertical-align: middle;
padding-top: 0.25rem;
padding-bottom: 0.5rem;
font-weight: bold;
outline: solid 1px black;
margin-top: 2rem;
}
.ladder-element {
background-color: #1c1c1c;
vertical-align: middle;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
outline: solid 1px black;
}
.ladder-element-dark {
background-color: #131313;
}
.ladder-element-achieved {
background-color: rgba(50, 205, 50, 0.2);
}
.ladder-element-unachieved {
background-color: rgba(170, 85, 85, 0.2);
}
.timeline-element {
background-color: #1c1c1c;
border-radius: 1rem;
padding: 1rem;
margin-top: 1rem;
}
.custom-switch {
padding: 0 !important;
}
.instructions-list {
font-size: 1.2rem;
}
.instructions-list > li {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
.scoreinfo-grid-minimap {
display: grid;
grid-template-columns: repeat(auto-fill, 30px);
row-gap: 5px;
column-gap: 2px;
justify-items: center;
}
.scoreinfo-grid-minimap-element {
width: 20px;
height: 20px;
outline: 1px black solid;
display: flex;
justify-content: center;
align-content: center;
text-align: center;
color: white;
font-weight: 900;
}
.scoreinfo-grid-minimap-element-recent {
box-shadow: inset 0px 0px 5px goldenrod;
}
.privacy-policy > h2 {
margin-top: 1rem;
}
.breakdown-hover-row:hover .breakdown-hover-highlight-button {
opacity: 1;
}
.breakdown-hover-highlight-button {
transition: opacity 0.3s;
opacity: 0;
}
-43
View File
@@ -1,43 +0,0 @@
.landing-page {
.hero {
width: 100vw;
height: 100vh;
.hero-bg-image {
width: 100vw;
height: 100vh;
z-index: 1;
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
position: absolute;
}
.hero-bg-fader {
width: 100vw;
height: 100vh;
z-index: 2;
opacity: 0.75;
position: absolute;
}
.hero-content-wrapper {
width: 100vw;
height: 100vh;
z-index: 3;
position: absolute;
}
.hero-content-wrapper > .row {
height: calc(100vh - 150px);
}
@media only screen and (max-width: 600px) {
.hero-content-wrapper > .row {
height: calc(100vh - 80px);
}
}
}
}
@@ -1,60 +0,0 @@
body {
margin: 0;
padding: 0;
}
#splash-screen {
position: absolute;
z-index: 1000;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: #131313;
}
#splash-screen img {
margin-left: calc(100vw - 100%);
margin-bottom: 30px;
}
#splash-screen.hidden {
opacity: 0;
visibility: hidden;
}
.splash-spinner {
animation: rotate 2s cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
margin-left: calc(100vw - 100%);
width: 50px;
height: 50px;
}
.splash-spinner .path {
stroke: #e61c6e;
stroke-linecap: round;
animation: dash 1.5s ease-in-out infinite;
}
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes dash {
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
}
@@ -1,5 +1,4 @@
import { APIFetchV1 } from "util/api";
import { ChangeOpacity } from "util/color-opacity";
import { CreateGoalMap } from "util/data";
import { RFA } from "util/misc";
import { NumericSOV } from "util/sorts";
@@ -18,11 +17,13 @@ import Loading from "components/util/Loading";
import useApiQuery from "components/util/query/useApiQuery";
import { UserContext } from "context/UserContext";
import { UserSettingsContext } from "context/UserSettingsContext";
import { ColourConfig, TachiConfig } from "lib/config";
import { TachiConfig } from "lib/config";
import React, { useContext, useMemo } from "react";
import { Alert, Stack } from "react-bootstrap";
import Alert from "react-bootstrap/Alert";
import Stack from "react-bootstrap/Stack";
import Row from "react-bootstrap/Row";
import { Link, Route, Switch } from "react-router-dom";
import { COLOUR_SET, GetGameConfig, UserDocument } from "tachi-common";
import { GetGameConfig, UserDocument } from "tachi-common";
import { UGSWithRankingData, UserRecentSummary } from "types/api-returns";
import SessionCalendar from "components/sessions/SessionCalendar";
import { WindowContext } from "context/WindowContext";
@@ -101,39 +102,32 @@ function RecentInfo({ user }: { user: UserDocument }) {
<>
{data.recentSessions.length !== 0 && (
<>
<Alert
style={{
backgroundColor: `${ColourConfig.primary}44`,
color: "white",
}}
>
<Alert variant="primary">
<div className="text-center">
<h1>Today's Summary</h1>
You've gotten <b>{data.recentPlaycount}</b> new score
{data.recentPlaycount !== 1 ? "s" : ""} today!
</div>
</Alert>
<Divider />
<h1>New Sessions</h1>
You've had <b>{data.recentSessions.length}</b> session
{data.recentSessions.length !== 1 ? "s" : ""} today!
<Divider />
<hr />
<div className="text-center">
<h1>New Sessions</h1>
You've had <b>{data.recentSessions.length}</b> session
{data.recentSessions.length !== 1 ? "s" : ""} today!
</div>
<hr />
{data.recentSessions.sort(NumericSOV((x) => x.timeEnded, true)).map((e) => (
<>
<SessionCard sessionID={e.sessionID} key={e.sessionID} />
<Divider />
<hr />
</>
))}
</>
)}
{data.recentAchievedGoals.length !== 0 && (
<>
<Alert
style={{
backgroundColor: ChangeOpacity(COLOUR_SET.gold, 0.2),
}}
>
<div className="text-center text-white">
<Alert variant="warning">
<div className="text-center">
<h1>
{RFA([
"Sweet!",
@@ -149,8 +143,8 @@ function RecentInfo({ user }: { user: UserDocument }) {
You've achieved <b>{data.recentAchievedGoals.length}</b> new goal
{data.recentAchievedGoals.length !== 1 ? "s" : ""} today!
</div>
<Divider />
<div className="text-white">
<hr />
<div>
<ul>
{data.recentAchievedGoals.map((e) => {
const goal = goalMap.get(e.goalID);
@@ -196,7 +190,7 @@ function RecentInfo({ user }: { user: UserDocument }) {
function UserGameStatsInfo({ user }: { user: UserDocument }) {
return (
<div className="row">
<Row xs={{ cols: 1 }} lg={{ cols: 2 }}>
<AsyncLoader
promiseFn={async () => {
const res = await APIFetchV1<UGSWithRankingData[]>(
@@ -230,7 +224,7 @@ function UserGameStatsInfo({ user }: { user: UserDocument }) {
))
}
</AsyncLoader>
</div>
</Row>
);
}
@@ -22,6 +22,7 @@ import {
integer,
UserDocument,
} from "tachi-common";
import Col from "react-bootstrap/Col";
export default function ImportPage({ user }: { user: UserDocument }) {
useSetSubheader(["Import Scores"]);
@@ -37,7 +38,7 @@ export default function ImportPage({ user }: { user: UserDocument }) {
}, [queryGame]);
return (
<div>
<>
<div>
<h4>
Here, you can import score files, Synchronise with existing services, or set up
@@ -47,15 +48,21 @@ export default function ImportPage({ user }: { user: UserDocument }) {
<DiscordLink>Discord</DiscordLink>.
<br />
Know how to program, and want to write a script yourself? Check out{" "}
<ExternalLink href="https://docs.bokutachi.xyz/codebase/batch-manual">
<ExternalLink
className="text-decoration-underline"
href="https://docs.bokutachi.xyz/codebase/batch-manual"
>
Batch Manual
</ExternalLink>
.
<br />
Want to manage or revert an import? Go to{" "}
<Link to={`/u/${user.username}/imports`}>Import Management</Link>.
<Link className="text-decoration-underline" to={`/u/${user.username}/imports`}>
Import Management
</Link>
.
</div>
<Divider />
<hr />
<Form.Select
onChange={(e) => setGame(e.target.value === "" ? null : (e.target.value as Game))}
value={game ?? ""}
@@ -67,10 +74,10 @@ export default function ImportPage({ user }: { user: UserDocument }) {
</option>
))}
</Form.Select>
<Divider />
<hr />
{game ? <ImportInfoDisplayer game={game} /> : <ShowRecentImports />}
</div>
</>
);
}
@@ -306,7 +313,9 @@ function ImportInfoDisplayer({ game }: { game: Game }) {
<div className="text-center mb-4">
<h1>{gameConfig.name}</h1>
</div>
<div className="row justify-content-center">{Content}</div>
<Row xs={{ cols: 1 }} lg={{ cols: 2 }}>
{Content}
</Row>
</>
);
}
@@ -565,8 +574,9 @@ function ImportInfoCard({
moreInfo?: React.ReactChild;
}) {
return (
<div className="col-12 col-lg-6 mb-6 d-grid">
<Col className="p-2 flex-grow-1">
<Card
className="h-100"
header={name}
footer={
<LinkButton className="float-end" to={`/import/${href}`}>
@@ -582,6 +592,6 @@ function ImportInfoCard({
</>
)}
</Card>
</div>
</Col>
);
}
@@ -11,6 +11,8 @@ import ReferToUser from "components/util/ReferToUser";
import React from "react";
import { FormatGame, UserDocument, UserGameStats } from "tachi-common";
import { UGSWithRankingData } from "types/api-returns";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
interface Props {
reqUser: UserDocument;
@@ -24,7 +26,7 @@ export default function UserGamesPage({ reqUser }: Props) {
);
return (
<div className="row">
<Row xs={{ cols: 1 }} lg={{ cols: 2 }}>
<AsyncLoader
promiseFn={async () => {
const res = await APIFetchV1<UGSWithRankingData[]>(
@@ -50,7 +52,7 @@ export default function UserGamesPage({ reqUser }: Props) {
)
}
</AsyncLoader>
</div>
</Row>
);
}
@@ -80,9 +82,9 @@ function GamesInfo({ ugs, reqUser }: { ugs: UserGameStats[]; reqUser: UserDocume
export function GameStatContainer({ ugs, reqUser }: { ugs: UGSWithRankingData } & Props) {
return (
<div className="col-12 col-lg-6 d-grid">
<Col className="p-2 flex-grow-1">
<Card
className="mb-4"
className="h-100"
footer={
<div className="d-flex justify-content-end">
<LinkButton to={`/u/${reqUser.username}/games/${ugs.game}/${ugs.playtype}`}>
@@ -100,6 +102,6 @@ export function GameStatContainer({ ugs, reqUser }: { ugs: UGSWithRankingData }
userID={ugs.userID}
/>
</Card>
</div>
</Col>
);
}
@@ -50,6 +50,7 @@ export default function SpecificSessionPage({ reqUser, game, playtype }: UGPT) {
function SessionPage({ data, game, playtype }: UGPT & { data: SessionReturns }) {
const { settings } = useContext(UserSettingsContext);
const [sessionData, setSessionData] = useState(data);
const { session, user, charts, scores, songs } = sessionData;
@@ -108,6 +109,9 @@ function SessionPage({ data, game, playtype }: UGPT & { data: SessionReturns })
const [highlight, setHighlight] = useState(session.highlight);
const isAuthorised =
loggedInUser && (loggedInUser.authLevel === 3 || loggedInUser.id === user.id);
const updateSession = (sessionData: SessionReturns) => {
APIFetchV1(
`/sessions/${sessionData.session.sessionID}`,
@@ -130,13 +134,12 @@ function SessionPage({ data, game, playtype }: UGPT & { data: SessionReturns })
return (
<Row className="justify-content-center">
<Col xs={12} className="text-center">
<div
className="d-flex flex-wrap justify-content-center align-items-center"
style={{ flexDirection: "column" }}
>
<div className="d-flex flex-column gap-2 flex-wrap justify-content-center align-items-center">
<EditableText
as="h1"
className="enable-rfs"
initial={session.name}
onChange={(name) => {
onSubmit={(name) => {
const newSession: SessionReturns = {
...sessionData,
session: {
@@ -149,20 +152,13 @@ function SessionPage({ data, game, playtype }: UGPT & { data: SessionReturns })
updateSession(newSession);
}}
>
{(text) => (
<div className="mb-4">
<span className="display-4">{text}</span>
<span className="ms-2 text-hover-white">
<Icon type="pencil-alt" />
</span>
</div>
)}
</EditableText>
authorised={isAuthorised || false}
/>
<EditableText
initial={session.desc ?? "No Description..."}
onChange={(desc) => {
className="fs-5"
onSubmit={(desc) => {
const newSession: SessionReturns = {
...sessionData,
session: {
@@ -175,17 +171,8 @@ function SessionPage({ data, game, playtype }: UGPT & { data: SessionReturns })
updateSession(newSession);
}}
>
{(text) => (
<div className="mb-4">
<span className="text-body-secondary mb-4">{text}</span>
<span className="ms-2 text-hover-white">
<Icon type="pencil-alt" />
</span>
</div>
)}
</EditableText>
authorised={isAuthorised || false}
/>
</div>
{session.highlight && (
<Badge
@@ -225,7 +212,7 @@ function SessionPage({ data, game, playtype }: UGPT & { data: SessionReturns })
);
}}
>
Un-Highlight Session
<Icon type="star" /> Un-Highlight Session
</Button>
) : (
<Button
@@ -250,7 +237,7 @@ function SessionPage({ data, game, playtype }: UGPT & { data: SessionReturns })
);
}}
>
Highlight Session
<Icon regular type="star" /> Highlight Session
</Button>
)}
<Divider />
@@ -610,7 +610,7 @@ function TierlistBucket({
}
return (
<div className="grid text-center gap-2 g-columns-md-4 g-columns-lg-5 g-columns-xl-6">
<div className="grid text-center gap-2 grid-cols-md-4 grid-cols-lg-5 grid-cols-xl-6">
{bucket.map((tierlistInfo, i) => (
<TierlistInfoBucketValues
tierlistInfo={tierlistInfo}
@@ -17,7 +17,7 @@ export function DashboardLoggedInNoScores({ user }: { user: UserDocument }) {
<br />
You'll get a profile for that game, and a position on the leaderboards!
</h4>
<LinkButton className="btn-outline-primary" to="/import">
<LinkButton variant="outline-primary" to="/import">
Import some scores!
</LinkButton>
</div>
@@ -5,7 +5,7 @@ import QuickDropdown from "components/ui/QuickDropdown";
import DropdownNavLink from "components/ui/DropdownNavLink";
import { SetState } from "types/react";
export default function AllGames({
export default function GlobalInfoDropdown({
className,
menuClassName,
style,
@@ -39,8 +39,8 @@ export default function Header({ styles }: { styles: LayoutStyles }) {
<Logo />
<MobileMenuToggle state={showMobileMenu} setState={setShowMobileMenu} />
<Navbar.Offcanvas
id="mobile-menu"
aria-labelledby="mobile-menu-label"
id="navbar"
aria-labelledby="navbar-label"
show={showMobileMenu}
onHide={() => setShowMobileMenu(false)}
>
@@ -50,7 +50,7 @@ export default function Header({ styles }: { styles: LayoutStyles }) {
to="/"
className="mx-auto p-2 focus-ring focus-ring-light"
>
<SiteWordmark id="mobile-menu-label" width="192px" />
<SiteWordmark id="navbar-label" width="192px" />
</Link>
</OffcanvasHeader>
<Offcanvas.Body className="position-relative">
@@ -5,13 +5,13 @@ import { UserDocument, UserGameStats } from "tachi-common";
import useApiQuery from "components/util/query/useApiQuery";
import Nav from "react-bootstrap/Nav";
import { SetState } from "types/react";
import AllGames from "./AllGames";
import ImportScoresLink from "./ImportScoresLink";
import GlobalInfoDropdown from "./GlobalInfoDropdown";
import ImportScoresDropdown from "./ImportScoresDropdown";
import UtilsDropdown from "./UtilsDropdown";
import UserProfileLinks from "./UserProfileLinks";
import UGPTDropdown from "./UGPTDropdown";
const toggleClassNames = "w-100 justify-content-between";
const menuClassNames = "shadow-none shadow-lg-md";
const menuClassNames = "shadow-none shadow-lg-lg";
export function HeaderMenu({
user,
@@ -41,9 +41,9 @@ export function HeaderMenu({
}, [error, data]);
return (
<Nav className="p-4 d-flex flex-column flex-lg-row align-content-between gap-2 gap-lg-4 overflow-y-auto overflow-y-lg-visible scrollbar-hide h-100">
<Nav as="nav" className="p-4 d-flex align-content-between gap-4 h-100">
{user && ugs && ugs.length !== 0 && (
<UserProfileLinks
<UGPTDropdown
user={user}
ugs={ugs}
className={toggleClassNames}
@@ -52,14 +52,14 @@ export function HeaderMenu({
setState={setState}
/>
)}
<AllGames
<GlobalInfoDropdown
className={toggleClassNames}
menuClassName={menuClassNames}
style={dropdownMenuStyle}
setState={setState}
/>
{user && (
<ImportScoresLink
<ImportScoresDropdown
className={toggleClassNames}
menuClassName={menuClassNames}
style={dropdownMenuStyle}
@@ -1,63 +0,0 @@
import { ToAPIURL } from "util/api";
import { UserContext } from "context/UserContext";
import React, { useContext } from "react";
import { Link } from "react-router-dom";
import { SetState } from "types/react";
import { UserNotificationButton } from "./UserNotificationButton";
import { SearchButton } from "./SearchButton";
export function HeaderMobile({
mobileShow,
setMobileShow,
}: {
mobileShow: boolean;
setMobileShow: SetState<boolean>;
}) {
const { user } = useContext(UserContext);
return (
<>
<div id="kt_header_mobile" className="header-mobile header-mobile-fixed">
<div className="d-flex align-items-center justify-content-start">
<button
className="btn p-0 burger-icon burger-icon-right ms-2 me-auto"
id="kt_header_mobile_toggle"
onClick={() => setMobileShow(!mobileShow)}
>
<span />
</button>
</div>
<div className="d-flex align-items-center">
<SearchButton />
{user ? (
<>
<UserNotificationButton />
<button
className="btn btn-icon btn-hover-transparent-white p-0 ms-3"
id="kt_header_mobile_topbar_toggle"
>
<Link to={`/u/${user.username}`}>
<div className="px-4">
<img
className="rounded"
src={ToAPIURL("/users/me/pfp")}
style={{
width: "30px",
height: "30px",
display: "inline-block",
}}
/>
</div>
</Link>
</button>
</>
) : (
<></>
)}
</div>
</div>
</>
);
}
+2 -2
View File
@@ -6,9 +6,9 @@ import { TachiConfig } from "lib/config";
export default function Logo() {
return (
<Link
id="home"
id="top"
to="/"
className="p-2 d-none d-lg-block focus-ring focus-ring-primary transition-color transition-box-shadow rounded"
className="p-2 d-none d-lg-block focus-visible-ring focus-ring-primary transition-color transition-box-shadow rounded"
>
<img
id="logo"
@@ -1,34 +0,0 @@
import useComponentVisible from "components/util/useComponentVisible";
import React from "react";
import { JustChildren } from "types/react";
export default function MenuDropdown({ name, children }: { name: string } & JustChildren) {
const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(false);
return (
<li
ref={ref}
data-menu-toggle="click"
aria-haspopup="true"
className={`menu-item menu-item-submenu menu-item-rel menu-item-open-dropdown ${
isComponentVisible ? "menu-item-active-tab" : ""
}`}
onClick={() => setIsComponentVisible(!isComponentVisible)}
>
<div className="menu-link menu-toggle">
<span className="menu-text">{name}</span>
<i className="menu-arrow" />
</div>
<div
style={{
display: isComponentVisible ? "block" : "none",
}}
className="menu-submenu menu-submenu-classic menu-submenu-left"
>
<ul className="menu-subnav">{children}</ul>
</div>
</li>
);
}
// .header-menu .menu-nav .menu-item.menu-item-active-tab .menu-submenu, .header-menu .menu-nav .menu-item.menu-item-hover .menu-submenu
@@ -1,302 +0,0 @@
import { APIFetchV1 } from "util/api";
import { ConditionalLeadingSpace, PREVENT_DEFAULT } from "util/misc";
import Divider from "components/util/Divider";
import Icon from "components/util/Icon";
import Loading from "components/util/Loading";
import { TachiConfig } from "lib/config";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import { Game, GetGameConfig, integer, UserDocument, SongDocument, Playtype } from "tachi-common";
import { GamePT, JustChildren } from "types/react";
import QuickTooltip from "../misc/QuickTooltip";
interface SearchReturns {
users?: UserDocument[];
songs: (SongDocument & { __textScore: number; game: Game })[];
}
function SearchResult({
children,
link,
tabIndex,
}: JustChildren & { link: string; tabIndex?: integer }) {
return (
<Link
className="d-flex align-items-center flex-grow-1 mb-2 search-result"
tabIndex={tabIndex}
to={link}
>
<div className="d-flex flex-column ms-3 mt-2 mb-2">{children}</div>
</Link>
);
}
function GPTSearchResult({
user,
game,
playtype,
tabIndex,
}: {
user: UserDocument;
tabIndex: integer;
} & GamePT) {
const currentLoc = window.location.href.split(`games/${game}/${playtype}`)[1];
return (
<div className="d-flex flex-column ms-3 mt-2 mb-2">
<strong>
<Link to={`/u/${user.username}`}>{user.username}</Link>
<Link
className="float-end gentle-link me-4"
tabIndex={tabIndex}
to={`/u/${user.username}/games/${game}/${playtype}${currentLoc}`}
style={{
fontWeight: "lighter",
}}
>
<QuickTooltip tooltipContent={`Go to this page, but for ${user.username}.`}>
<span>
<Icon type="exchange-alt" />
</span>
</QuickTooltip>
</Link>
</strong>
<span className="font-size-sm fw-bold text-body-secondary">{user.status}</span>
</div>
);
}
function SearchResults({ results }: { results: SearchReturns }) {
if (!results.users?.length && !results.songs.length) {
return (
<div className="font-size-sm fw-bolder text-uppercase mb-2 text-center">
Found nothing :(
</div>
);
}
// useParams doesn't do what i think it does, so...
// here's a hack.
const params = useLocation<{ game?: Game; playtype?: Playtype }>();
const { game, playtype, user } = useMemo(() => {
const regexp = `/games/(${TachiConfig.games.join("|")})/[^/]*/?`;
if (params.pathname.match(new RegExp(regexp, "u"))) {
const hack = params.pathname.split("/games/")[1].split("/");
return {
game: hack[0] as Game,
playtype: hack[1] as Playtype,
user: params.pathname.match(/\/dashboard\/users\/(.*?)\//u)?.[1],
};
}
return { game: null, playtype: null };
}, [params.pathname]);
return (
<div className="quick-search-result">
{results?.users?.length ? (
<>
<div className="font-size-sm text-primary fw-bolder text-uppercase mb-2">
Users
</div>
<div>
{results.users.map((u) =>
game && playtype && user ? (
<GPTSearchResult
key={u.id}
game={game}
playtype={playtype}
tabIndex={0}
user={u}
/>
) : (
<SearchResult key={u.id} link={`/u/${u.username}`} tabIndex={0}>
<strong>{u.username}</strong>
<span className="font-size-sm fw-bold text-body-secondary">
{u.status}
</span>
</SearchResult>
)
)}
</div>
<Divider className="mt-2 mb-4" />
</>
) : (
<></>
)}
{results?.songs.length ? (
<>
<div className="font-size-sm text-primary fw-bolder text-uppercase mb-2">
Songs
</div>
<div className="mb-4">
{results.songs.map((s) => (
<SearchResult
key={s.id + s.game}
link={`/games/${s.game}/${
GetGameConfig(s.game).playtypes.includes(playtype as Playtype)
? playtype
: GetGameConfig(s.game).playtypes[0]
}/songs/${s.id}`}
tabIndex={0}
>
<strong>{FormatSongTitle(s.game, s)}</strong>
<span className="font-size-sm fw-bold text-body-secondary">
{GetGameConfig(s.game).name}
</span>
</SearchResult>
))}
</div>
</>
) : (
<></>
)}
</div>
);
}
function FormatSongTitle(game: Game, song: SongDocument) {
if (game === "bms" || game === "pms") {
const s = song as SongDocument<"bms" | "pms">;
return `${song.title}${ConditionalLeadingSpace(s.data.subtitle)}${ConditionalLeadingSpace(
s.data.tableString
)}`;
}
if (game === "itg") {
const s = song as SongDocument<"itg">;
return `${song.title}${ConditionalLeadingSpace(s.data.subtitle)}`;
}
return song.title;
}
export default function SearchBar() {
const [show, setShow] = useState(false);
const [search, setSearch] = useState("");
const [results, setResults] = useState<SearchReturns | null>(null);
const [lastTimeout, setLastTimeout] = useState<number | null>(null);
const ref = useRef(null);
const inputRef = useRef(null);
// onclick outside
useEffect(() => {
function clickOutside(event: MouseEvent) {
// @ts-expect-error lazy
if (ref.current && !ref.current.contains(event.target)) {
setShow(false);
}
}
document.addEventListener("mousedown", clickOutside);
return () => {
document.removeEventListener("mousedown", clickOutside);
};
}, [ref]);
useEffect(() => {
setShow(search !== "");
}, [search]);
// debouncer result-getter
function UpdateSearch(event: React.ChangeEvent<HTMLInputElement>) {
setSearch(event.target.value);
if (lastTimeout !== null) {
clearTimeout(lastTimeout);
}
const closureSearch = event.target.value;
// compatibility note - we use window here to specify to typescript
// that this is NOT the node version of setTimeout() (which does not return a number).
const handle = window.setTimeout(() => {
const searches = [];
searches.push(
APIFetchV1<SearchReturns>(`/search?search=${encodeURIComponent(closureSearch)}`)
);
if (TachiConfig.type !== "ktchi") {
searches.push(
APIFetchV1<SearchReturns>(
`/search/chart-hash?search=${encodeURIComponent(closureSearch)}`
)
);
}
Promise.all(searches).then((results) => {
const setValue: SearchReturns = {
users: [],
songs: [],
};
for (const result of results) {
if (result.success === false) {
console.error(result);
return;
}
setValue.songs.push(...result.body.songs);
setValue.users!.push(...(result.body.users ?? []));
}
setResults(setValue);
});
}, 250);
setLastTimeout(handle);
}
return (
<div ref={ref} className="align-self-center" style={{ flexGrow: 1 }}>
<div className="topbar-item me-2">
<form className="quick-search-form" onSubmit={PREVENT_DEFAULT}>
<div className="input-group">
<input
className="form-control"
type="text"
ref={inputRef}
value={search}
onChange={UpdateSearch}
onClick={() => {
if (search !== "") {
setShow(true);
}
}}
placeholder="Search users, songs, charts..."
/>
</div>
</form>
</div>
<div style={{ position: "relative", top: "20px" }}>
<div
className={`dropdown-menu p-0 m-0 dropdown-menu-right dropdown-menu-anim-up dropdown-menu-lg dropdown-menu dropdown-menu-right ${
show ? "show" : "hide"
}`}
style={{
position: "absolute",
borderRadius: "0 0 5px 5px",
}}
>
<div
id="kt_quick_search_dropdown"
className="quick-search quick-search-dropdown quick-search-has-result"
>
<div
style={{ maxHeight: "325px", overflowY: "auto" }}
className="quick-search-wrapper"
>
{results ? <SearchResults results={results} /> : <Loading />}
</div>
</div>
</div>
</div>
</div>
);
}
@@ -1,34 +0,0 @@
import { UserProfileDropdown } from "components/layout/header/UserProfileDropdown";
import LinkButton from "components/util/LinkButton";
import { UserContext } from "context/UserContext";
import React, { useContext } from "react";
import { UserNotificationButton } from "./UserNotificationButton";
import { SearchButton } from "./SearchButton";
export function Topbar() {
const { user } = useContext(UserContext);
return (
<div className="topbar" style={{ minWidth: "35%" }}>
<SearchButton />
{user ? (
<>
<UserNotificationButton />
<UserProfileDropdown user={user} />
</>
) : (
<>
<div className="topbar-item me-3">
<LinkButton to="/login" className="btn-outline-primary">
Log In
</LinkButton>
</div>
<div className="topbar-item">
<LinkButton to="/register">Create Account</LinkButton>
</div>
</>
)}
</div>
);
}
@@ -5,7 +5,7 @@ import React from "react";
import { FormatGame, GetGameConfig, UserDocument, UserGameStats } from "tachi-common";
import { SetState } from "types/react";
export default function UserProfileLinks({
export default function UGPTDropdown({
user,
ugs,
className,
@@ -11,8 +11,9 @@ export function Breadcrumbs({ items }: { items: string[] }) {
return (
<div className="d-none d-lg-flex align-items-center fw-semibold">
<Link
className="link-body-emphasis link-opacity-75 link-opacity-100-hover transition-color"
className="p-1 rounded link-body-emphasis link-opacity-75 link-opacity-100-hover focus-visible-ring transition-color"
to="/"
aria-label="Home"
>
<Icon type="home" />
</Link>
@@ -33,7 +34,7 @@ export function Breadcrumbs({ items }: { items: string[] }) {
className="h-2 w-2 d-block bg-body-emphasis rounded-circle bg-opacity-75 mx-3"
/>
<Link
className="link-body-emphasis link-opacity-75 link-opacity-100-hover transition-color"
className="p-1 rounded link-body-emphasis link-opacity-75 link-opacity-100-hover focus-visible-ring transition-color"
to={`/${parts.slice(0, index + 1).join("/")}`}
>
{name}
+8 -19
View File
@@ -13,7 +13,8 @@ import Muted from "components/util/Muted";
import useApiQuery from "components/util/query/useApiQuery";
import { UserContext } from "context/UserContext";
import React, { useContext, useMemo, useState } from "react";
import { Button } from "react-bootstrap";
import Button from "react-bootstrap/Button";
import Row from "react-bootstrap/Row";
import toast from "react-hot-toast";
import { SessionDocument } from "tachi-common";
import { SessionReturns } from "types/api-returns";
@@ -71,7 +72,7 @@ export default function SessionCard({ sessionID }: { sessionID: string }) {
/>
<Divider />
{sessionUser.id === user?.id && (
<div className="d-flex w-100 justify-content-center">
<div className="d-flex w-100 gap-4 justify-content-center">
<Button
onClick={async () => {
const res = await APIFetchV1(
@@ -101,12 +102,12 @@ export default function SessionCard({ sessionID }: { sessionID: string }) {
}}
variant={highlight ? "outline-danger" : "outline-warning"}
>
<Icon type="star" />
<Icon type="star" regular={!highlight} />{" "}
{highlight ? "Remove as Highlight" : "Highlight this session!"}
</Button>
<LinkButton
to={`/u/${sessionUser.username}/games/${session.game}/${session.playtype}/sessions/${session.sessionID}`}
className="ms-4 btn-primary"
className="btn-primary"
>
View Session
</LinkButton>
@@ -118,31 +119,19 @@ export default function SessionCard({ sessionID }: { sessionID: string }) {
function SessionOverview({ session, username }: { session: SessionDocument; username: string }) {
return (
<div className="row">
<Row xs={{ cols: 1 }} lg={{ cols: 2 }}>
<StatIcon name="Scores" value={session.scoreIDs.length} />
<div className="col-12 col-lg-4">
<div className="d-flex justify-content-center align-self-center">
<LinkButton
to={`/u/${username}/games/${session.game}/${session.playtype}/sessions/${session.sessionID}`}
className="btn-primary"
>
View Session
</LinkButton>
</div>
</div>
<StatIcon
name="Duration"
value={FormatDuration(session.timeEnded - session.timeStarted)}
/>
</div>
</Row>
);
}
function StatIcon({ name, value }: { name: string; value: React.ReactChild }) {
return (
<div className="col-12 col-lg-4 text-center">
<div className="col text-center">
<h4>
<Muted>{name}</Muted>
</h4>
@@ -183,7 +183,6 @@ export default function TachiTable<D>({
<div className="d-none d-lg-flex col-lg-4 justify-content-center align-items-center">
{settings?.preferences.developerMode && (
<Button
className="ms-4 w-50"
onClick={() => {
let data = dataset;
if (search !== "") {
@@ -202,7 +201,7 @@ export default function TachiTable<D>({
<div className="col-lg-4 ms-auto text-end">
<div className="btn-group">
<Button
variant="secondary"
variant="base"
disabled={pageState === "start" || pageState === "start-end"}
onClick={decrementPage}
>
@@ -210,7 +209,7 @@ export default function TachiTable<D>({
</Button>
<PageSelector currentPage={page} maxPage={maxPage} setPage={setPage} />
<Button
variant="secondary"
variant="base"
disabled={pageState === "end" || pageState === "start-end"}
onClick={incrementPage}
>
@@ -3,10 +3,11 @@ import { UppercaseFirst } from "util/misc";
import TimestampCell from "components/tables/cells/TimestampCell";
import ScoreCoreCells from "components/tables/game-core-cells/ScoreCoreCells";
import useScoreRatingAlg from "components/util/useScoreRatingAlg";
import React, { useEffect, useState } from "react";
import React, { useContext, useEffect, useState } from "react";
import { ChartDocument, PBScoreDocument, ScoreDocument } from "tachi-common";
import { UGPTChartPBComposition } from "types/api-returns";
import { SetState } from "types/react";
import { UserContext } from "context/UserContext";
import CommentContainer from "./CommentContainer";
import JudgementTable from "./JudgementTable";
import PBNote from "./PBNote";
@@ -100,6 +101,9 @@ export default function DocumentComponent({
scoreState.setComment?.(comment);
}, [comment]);
const { user } = useContext(UserContext);
const isAuthorised = user && (user.id === score.userID || user.authLevel === 3);
return (
<div className="w-100 h-100 mb-0 d-flex" style={{ gap: "10px" }}>
<div style={{ flex: 9 }}>
@@ -162,7 +166,7 @@ export default function DocumentComponent({
<JudgementTable score={score} />
</div>
{IsScore(score) && (
{IsScore(score) && isAuthorised && (
<div>
<DeleteScoreBtn score={score} />
</div>
@@ -36,18 +36,18 @@ export default function ScoreEditButtons({
<>
<QuickTooltip tooltipContent="Edit your comment on this score.">
<Button
variant="outline-secondary"
variant="outline-secondary text-light-hover"
className="text-body"
onClick={() => setShow(true)}
>
<Icon type="file-signature" /> Comment
<Icon type="file-signature" /> Edit Comment
</Button>
</QuickTooltip>
</>
) : (
<QuickTooltip tooltipContent="Comment on this score.">
<Button
variant="outline-secondary"
variant="outline-secondary text-light-hover"
className="text-body"
onClick={() => setShow(true)}
>
@@ -59,7 +59,7 @@ export default function ScoreEditButtons({
{highlight ? (
<QuickTooltip tooltipContent="Unhighlight this score.">
<Button
variant="success"
variant="outline-danger"
onClick={() =>
ModifyScore(score.scoreID, { highlight: false }).then(
(r) => {
@@ -79,7 +79,7 @@ export default function ScoreEditButtons({
<QuickTooltip tooltipContent="Highlight this score.">
<Button
variant="outline-secondary"
className="text-body"
className="text-body text-light-hover"
onClick={() =>
ModifyScore(score.scoreID, { highlight: true }).then(
(r) => {
+6 -1
View File
@@ -9,7 +9,12 @@ export default function DropdownNavLink({
...props
}: { to: string; children: React.ReactNode } & NavLinkProps) {
return (
<DropdownItem as={NavLink} to={to} className={`rounded ${className}`} {...props}>
<DropdownItem
as={NavLink}
to={to}
className={`rounded focus-visible-ring ${className}`}
{...props}
>
{children}
</DropdownItem>
);
+11 -4
View File
@@ -4,13 +4,20 @@ import Muted from "./Muted";
export default function DiscordLink({ children }: JustChildren) {
if (!process.env.VITE_DISCORD) {
<a href="#">
Discord <Muted>(However, no Discord has been set up yet...)</Muted>
</a>;
return (
<a href="#">
Discord <Muted>(However, no Discord has been set up yet...)</Muted>
</a>
);
}
return (
<a href={process.env.VITE_DISCORD} target="_blank" rel="noopener noreferrer">
<a
href={process.env.VITE_DISCORD}
className="text-decoration-underline"
target="_blank"
rel="noopener noreferrer"
>
{children}
</a>
);
+17 -11
View File
@@ -3,26 +3,31 @@ import { Button, Form, InputGroup } from "react-bootstrap";
import Icon from "./Icon";
export default function EditableText({
onChange,
children,
as = "p",
onSubmit,
initial,
authorised,
className,
}: {
onChange: (str: string) => void;
children: (text: string) => React.ReactNode;
as?: "p" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "span";
onSubmit: (value: string) => void;
initial: string;
authorised: boolean;
className?: string;
}) {
const [text, setText] = useState(initial);
const [editing, setEditing] = useState(false);
if (editing) {
return (
<InputGroup className="mb-2">
<InputGroup>
<Form.Control value={text} onChange={(e) => setText(e.target.value)} />
<Button
variant="success"
type="submit"
onClick={() => {
setEditing(false);
onChange(text);
onSubmit(text);
}}
>
Change
@@ -32,11 +37,12 @@ export default function EditableText({
}
return (
<div onClick={() => setEditing(true)} className="d-flex">
<div>{children(text)}</div>
<div>
<Icon type="pencil" />
</div>
<div
onClick={() => authorised && setEditing(true)}
className={`d-flex gap-2 ${authorised ? "cursor-pointer" : ""}`}
>
{React.createElement(as, { className }, text)}
{authorised && <Icon type="pencil-alt" />}
</div>
);
}
+1 -1
View File
@@ -1,7 +1,7 @@
import React from "react";
import ReactDOM from "react-dom";
import App from "app/App";
import "./styles/index.scss";
import "styles/main.scss";
import "@fortawesome/fontawesome-free/css/all.min.css";
const { PUBLIC_URL } = process.env;
@@ -3,9 +3,8 @@
// Bootstrap Variables Overrides
@import "bootstrap-scss/variables";
@import "./customised-bootstrap/variables";
@import "./customised-bootstrap/variables-dark";
@import "variables";
@import "variables-dark";
// Bootstrap Requirements
@import "bootstrap-scss/maps";
@@ -22,29 +21,17 @@
@import "bootstrap-scss/containers";
@import "bootstrap-scss/grid";
@import "bootstrap-scss/dropdown";
@import "customised-bootstrap/forms";
@import "bootstrap-scss/card";
@import "customised-bootstrap/badge";
@import "bootstrap-scss/alert";
@import "bootstrap-scss/offcanvas";
@import "bootstrap-scss/tables";
@import "bootstrap-scss/transitions";
@import "bootstrap-scss/tooltip";
@import "bootstrap-scss/toasts";
@import "bootstrap-scss/spinners";
@import "bootstrap-scss/nav";
@import "bootstrap-scss/navbar";
@import "bootstrap-scss/pagination";
@import "bootstrap-scss/modal";
@import "bootstrap-scss/close";
@import "customised-bootstrap/maps";
@import "customised-bootstrap/themes";
@import "customised-bootstrap";
@import "bootstrap-scss/utilities/api";
@import "legacy/base";
@import "globals";
@import "components/components";
@import "utilities/utilities";
@@ -0,0 +1,3 @@
@import "badge";
@import "forms";
@import "maps";
@@ -0,0 +1,249 @@
// known unused utilities are commented out. they can be added in and expanded when wanted
$utilities: map-merge(
$utilities,
(
"width": (
property: width,
class: w,
values: (
//1: 0.25rem,
2: 0.5rem,
//3: 0.75rem,
//4: 1.rem,
//6: 1.5em,
//8: 2rem,
//10: 2.5rem,
//12: 3rem,
14: 3.5rem,
//16: 4rem,
50: 50%,
//75: 75%,
100: 100%,
//"half": 50%,
"full": 100%,
auto: auto,
),
),
"height": (
property: height,
class: h,
responsive: true,
values: (
//1: 0.25rem,
2: 0.5rem,
//3: 0.75rem,
//4: 1.rem,
//6: 1.5em,
//8: 2rem,
//10: 2.5rem,
//12: 3rem,
14: 3.5rem,
//16: 4rem,
//50: 50%,
//75: 75%,
100: 100%,
//"half": 50%,
"full": 100%,
auto: auto,
),
),
"inset": (
property: inset,
class: inset,
values: (
0: 0,
//...
),
),
"animate": (
property: animation,
class: animate,
values: (
"fade-in": fade #{$transition-duration} ease-in forwards,
"fade-out": fade #{$transition-duration} ease-in backwards,
),
),
"backdrop-blur": (
property: backdrop-filter -webkit-backdrop-filter,
class: backdrop-blur,
values: (
//sm: blur(4px),
md: blur(8px),
//lg: blur(12px),
xl: blur(16px),
),
),
"background-color": (
property: background-color,
class: bg,
local-vars: (
"bg-opacity": 1,
),
state: hover,
values:
map-merge(
$utilities-bg-colors,
(
"transparent": transparent,
"body-secondary":
rgba(
var(--#{$prefix}secondary-bg-rgb),
var(--#{$prefix}bg-opacity)
),
"body-tertiary":
rgba(
var(--#{$prefix}tertiary-bg-rgb),
var(--#{$prefix}bg-opacity)
),
"body-emphasis":
rgba(
var(--#{$prefix}emphasis-color-rgb),
var(--#{$prefix}bg-opacity)
),
)
),
),
"subtle-background-color": (
property: background-color,
class: bg,
state: hover,
values: $utilities-bg-subtle,
),
/*"bg-opacity": (
css-var: true,
class: bg-opacity,
state: hover focus,
values: (
10: 0.1,
25: 0.25,
50: 0.5,
75: 0.75,
100: 1
)
),*/
"border-color":
(
property: border-color,
class: border,
local-vars: (
"border-opacity": 1,
),
values:
map-merge(
$utilities-border-colors,
(
body:
rgba(
var(--#{$prefix}body-bg-rgb),
var(--#{$prefix}border-opacity)
),
body-secondary:
rgba(
var(--#{$prefix}secondary-bg-rgb),
var(--#{$prefix}border-opacity)
),
body-tertiary:
rgba(
var(--#{$prefix}tertiary-bg-rgb),
var(--#{$prefix}border-opacity)
),
translucent: var(--#{$prefix}border-color-translucent),
)
),
),
"box-shadow": (
property: box-shadow,
class: shadow,
responsive: true,
state: focus,
values: (
"sm": var(--#{$prefix}box-shadow-sm),
"md": var(--#{$prefix}box-shadow),
"lg": var(--#{$prefix}box-shadow-lg),
//"inset": var(--#{$prefix}box-shadow-inset),
"none": none,
),
),
"color": (
property: color,
class: text,
local-vars: (
"text-opacity": 1,
),
state: (
hover,
focus,
),
values:
map-merge(
$utilities-text-colors,
(
"body-secondary": var(--#{$prefix}secondary-color),
"body-tertiary": var(--#{$prefix}tertiary-color),
"body-emphasis": var(--#{$prefix}emphasis-color),
"reset": inherit,
)
),
),
"text-color": (
property: color,
class: text,
state: hover,
values: $utilities-text-emphasis-colors,
),
"text-opacity": (
property: --#{$prefix}text-opacity,
class: text-opacity,
state: hover,
values: (
10: 10%,
25: 25%,
50: 50%,
75: 75%,
100: 100%,
),
),
"cursor": (
property: cursor,
class: cursor,
values: pointer not-allowed wait help default auto,
),
"transition": (
property: transition,
class: transition,
values: (
"color": color #{$transition-duration} ease-in-out,
"bg": background-color #{$transition-duration} ease-in-out,
"box-shadow": box-shadow #{$transition-duration} ease-in-out,
),
),
"overflow-y": (
property: overflow-y,
responsive: true,
values: auto hidden visible scroll,
),
"overflow-x": (
property: overflow-x,
responsive: true,
values: auto hidden visible scroll,
),
"overflow": (
property: overflow,
responsive: true,
values: auto hidden visible scroll,
),
"grid-rows": (
property: --#{$prefix}rows,
class: grid-rows,
responsive: true,
values: 1 2 3 4 5 6 7 8 9 10 11 12,
),
"grid-cols": (
property: --#{$prefix}columns,
class: grid-cols,
responsive: true,
values: 1 2 3 4 5 6 7 8 9 10 11 12,
),
)
);
@@ -552,7 +552,7 @@ $border-radius-pill: 50rem !default;
// scss-docs-start box-shadow-variables
$box-shadow-sm: 0 .025rem 0.175rem rgba($black, .1);
$box-shadow: 0 .05rem .45rem rgba($black, .075);
$box-shadow-lg: 0 .1rem 1.25rem rgba($black, .125);
$box-shadow-lg: 0 .075rem .9rem rgba($black, .1);
$box-shadow-inset: inset 0 0 6px rgba($body-bg, .15);
// scss-docs-end box-shadow-variables
@@ -749,7 +749,7 @@ $table-accent-bg: transparent;
$table-th-font-weight: null !default;
$table-striped-color: $table-color;
$table-striped-bg-factor: 0.075;
$table-striped-bg-factor: 0.05;
$table-striped-bg: rgba($black, $table-striped-bg-factor);
$table-active-color: $table-color;
@@ -757,7 +757,7 @@ $table-active-bg-factor: 0.0125;
$table-active-bg: rgba($black, $table-active-bg-factor);
$table-hover-color: $table-color;
$table-hover-bg-factor: 0.125;
$table-hover-bg-factor: 0.075;
$table-hover-bg: rgba($black, $table-hover-bg-factor);
$table-border-factor: 1;
+5
View File
@@ -0,0 +1,5 @@
@import "button";
@import "lamp-minimap";
@import "table";
@import "timeline";
@import "tooltip";
@@ -19,7 +19,7 @@
//--#{$prefix}btn-disabled-border-color: ;
--#{$prefix}btn-box-shadow: none;
--#{$prefix}btn-focus-box-shadow: #{$focus-ring-box-shadow};
&:focus {
&:focus-visible {
//color: var(--#{$prefix}btn-hover-color);
background-color: var(--#{$prefix}btn-hover-bg);
//border-color: var(--#{$prefix}btn-hover-border-color);
@@ -39,7 +39,7 @@
--#{$prefix}btn-active-shadow: var(--#{$prefix}box-shadow);
--#{$prefix}btn-disabled-bg: var(--#{$prefix}secondary-bg);
--#{$prefix}btn-disabled-border-color: transparent;
&:focus {
&:focus-visible {
box-shadow: var(--bs-btn-focus-box-shadow);
}
}
@@ -1,3 +0,0 @@
@import "Button";
@import "Table";
@import "Tooltip";
@@ -0,0 +1,23 @@
.scoreinfo-grid-minimap {
display: grid;
grid-template-columns: repeat(auto-fill, 30px);
row-gap: 5px;
column-gap: 2px;
justify-items: center;
&-element {
width: 20px;
height: 20px;
outline: 1px black solid;
display: flex;
justify-content: center;
align-content: center;
text-align: center;
color: white;
font-weight: 900;
}
&-element-recent {
box-shadow: inset 0px 0px 5px goldenrod;
}
}
@@ -1,3 +1,12 @@
table {
border-width: $table-border-width;
border-style: solid;
}
.table.table-vertical-center th, .table.table-vertical-center td {
vertical-align: middle;
}
.fading-image-td-left {
position: relative;
z-index: 1;
@@ -57,4 +66,10 @@
.fake-row {
border: none;
}
.highlighted-row {
td {
background-color: rgba($color: $primary, $alpha: 0.1);
}
}
@@ -0,0 +1,95 @@
.timeline {
position: relative;
.timeline-bar {
position: absolute;
display: block;
width: 1px;
height: 100%;
background-color: var(--bs-gray-400);
z-index: 2;
}
.timeline-item {
display: flex;
align-items: center;
width: 100%;
justify-content: space-between;
border-radius: var(--bs-border-radius);
margin: 0 0.5rem;
@include media-breakpoint-down(md) {
margin: 0.5rem 0;
padding: 0.5rem 0 !important;
position: relative;
}
&:after {
display: block;
width: 100%;
content: "";
position: absolute;
bottom: -0.275rem;
border-bottom: 1px var(--bs-secondary) solid;
}
&.timeline-hover:hover {
background-color: var(--bs-secondary-bg);
}
.timeline-badge {
height: 0.75rem;
width: 0.75rem;
border-radius: 100%;
position: absolute;
z-index: 3;
@include media-breakpoint-down(md) {
transform: translateX(-0.35rem);
}
@include media-breakpoint-up(md) {
transform: translateX(-0.835rem);
}
}
.timeline-content {
display: flex;
flex-direction: column;
flex-wrap: wrap;
padding: 1rem 1rem;
width: 100%;
&-inner {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
@include media-breakpoint-down(md) {
flex-wrap: wrap;
flex-direction: column;
}
}
&-title {
text-align: left;
@include media-breakpoint-up(lg) {
width: 70%;
}
@include media-breakpoint-down(md) {
display: block;
align-self: start;
}
}
&-timestamp {
text-align: right;
@include media-breakpoint-down(md) {
align-self: end;
margin: 0.5rem 0;
}
}
}
}
}
@@ -1,220 +0,0 @@
// known unused utilities are commented out. they can be added in and expanded when wanted
$utilities: map-merge(
$utilities,
(
"width": (
property: width,
class: w,
values: (
//1: 0.25rem,
2: 0.5rem,
//3: 0.75rem,
//4: 1.rem,
//6: 1.5em,
//8: 2rem,
//10: 2.5rem,
//12: 3rem,
14: 3.5rem,
//16: 4rem,
50: 50%,
//75: 75%,
100: 100%,
//"half": 50%,
"full": 100%,
auto: auto
)
),
"height": (
property: height,
class: h,
responsive: true,
values: (
//1: 0.25rem,
2: 0.5rem,
//3: 0.75rem,
//4: 1.rem,
//6: 1.5em,
//8: 2rem,
//10: 2.5rem,
//12: 3rem,
14: 3.5rem,
//16: 4rem,
//50: 50%,
//75: 75%,
100: 100%,
//"half": 50%,
"full": 100%,
auto: auto
)
),
"inset": (
property: inset,
class: inset,
values: (
0: 0,
//...
)
),
"animate": (
property: animation,
class: animate,
values: (
"fade-in": fade #{$transition-duration} ease-in forwards,
"fade-out": fade #{$transition-duration} ease-in backwards
)
),
"backdrop-blur": (
property: backdrop-filter -webkit-backdrop-filter,
class: backdrop-blur,
values: (
//sm: blur(4px),
md: blur(8px),
//lg: blur(12px),
xl: blur(16px)
)
),
"background-color": (
property: background-color,
class: bg,
local-vars: (
"bg-opacity": 1
),
state: hover,
values:
map-merge(
$utilities-bg-colors,
(
"transparent": transparent,
"body-secondary": rgba(var(--#{$prefix}secondary-bg-rgb), var(--#{$prefix}bg-opacity)),
"body-tertiary": rgba(var(--#{$prefix}tertiary-bg-rgb), var(--#{$prefix}bg-opacity)),
"body-emphasis": rgba(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}bg-opacity))
)
)
),
"subtle-background-color": (
property: background-color,
class: bg,
state: hover,
values: $utilities-bg-subtle
),
/*"bg-opacity": (
css-var: true,
class: bg-opacity,
state: hover focus,
values: (
10: 0.1,
25: 0.25,
50: 0.5,
75: 0.75,
100: 1
)
),*/
"border-color":
(
property: border-color,
class: border,
local-vars: (
"border-opacity": 1
),
values:
map-merge(
$utilities-border-colors,
(
body: rgba(var(--#{$prefix}body-bg-rgb), var(--#{$prefix}border-opacity)),
body-secondary: rgba(var(--#{$prefix}secondary-bg-rgb), var(--#{$prefix}border-opacity)),
body-tertiary: rgba(var(--#{$prefix}tertiary-bg-rgb), var(--#{$prefix}border-opacity)),
translucent: var(--#{$prefix}border-color-translucent)
)
)
),
"box-shadow": (
property: box-shadow,
class: shadow,
responsive: true,
state: focus,
values: (
"sm": var(--#{$prefix}box-shadow-sm),
"md": var(--#{$prefix}box-shadow),
//"lg": var(--#{$prefix}box-shadow-lg),
//"inset": var(--#{$prefix}box-shadow-inset),
"none": none
)
),
"color": (
property: color,
class: text,
local-vars: (
"text-opacity": 1
),
state: (
hover,
focus
),
values:
map-merge(
$utilities-text-colors,
(
"body-secondary": var(--#{$prefix}secondary-color),
"body-tertiary": var(--#{$prefix}tertiary-color),
"body-emphasis": var(--#{$prefix}emphasis-color),
"reset": inherit
)
)
),
"text-color": (
property: color,
class: text,
state: hover,
values: $utilities-text-emphasis-colors
),
"text-opacity": (
property: --#{$prefix}text-opacity,
class: text-opacity,
state: hover,
values: (
10: 10%,
25: 25%,
50: 50%,
75: 75%,
100: 100%
)
),
"transition": (
property: transition,
class: transition,
values: (
"color": color #{$transition-duration} ease-in-out,
"bg": background-color #{$transition-duration} ease-in-out,
"box-shadow": box-shadow #{$transition-duration} ease-in-out
)
),
"overflow-y": (
property: overflow-y,
responsive: true,
values: auto hidden visible scroll
),
"overflow-x": (
property: overflow-x,
responsive: true,
values: auto hidden visible scroll
),
"overflow": (
property: overflow,
responsive: true,
values: auto hidden visible scroll
),
"rows": (
property: --#{$prefix}rows,
class: g-rows,
responsive: true,
values: 1 2 3 4 5 6 7 8 9 10 11 12
),
"cols": (
property: --#{$prefix}columns,
class: g-columns,
responsive: true,
values: 1 2 3 4 5 6 7 8 9 10 11 12
)
)
);
+5 -5
View File
@@ -14,10 +14,10 @@
body,
header {
@extend .transition-bg;
@extend .transition-color;
}
/* debug
.undefined, .false, .true, .null {
color: yellow;
background-color: magenta;
}*/
code {
padding: #{$kbd-padding-y} #{$kbd-padding-x};
border-radius: var(--#{$prefix}border-radius-sm);
}
@@ -20,10 +20,6 @@
}
}
.topbar {
justify-content: end;
}
@include media-breakpoint-up(lg) {
.session-raise-container {
width: 100%;
@@ -42,4 +38,4 @@
opacity: 0.3;
}
@import "tachi-custom/custom", "tachi-custom/hero", "tachi-custom/splash-screen", "tachi-custom/timeline.scss";
@import "tachi-custom/custom", "tachi-custom/hero", "tachi-custom/splash-screen";
@@ -11,17 +11,6 @@
box-shadow: black 0px 0px 2px 1px !important;
}
.card-dark {
background-color: #1c1c1c !important;
> .card-header {
background-color: #1c1c1c !important;
}
> .card-footer {
background-color: #1c1c1c !important;
}
}
.gentle-link {
color: var(--bs-body-color);
@@ -30,73 +19,6 @@
}
}
@include media-breakpoint-down(sm) {
#kt_content {
padding-top: 55px;
}
.background-image {
top: 55px;
}
}
@include media-breakpoint-up(md) {
#kt_content {
padding-top: 80px;
}
.background-image {
top: 80px;
}
}
.highlighted-row {
td {
background-color: rgba($color: $primary, $alpha: 0.1);
}
}
.nav-link {
&:hover {
background-color: unset !important;
}
}
.text-monospace {
font-family: monospace;
}
.ladder-header {
background-color: #2b292b;
font-size: x-large;
vertical-align: middle;
padding-top: 0.25rem;
padding-bottom: 0.5rem;
font-weight: bold;
outline: solid 1px black;
margin-top: 2rem;
}
.ladder-element {
background-color: #1c1c1c;
vertical-align: middle;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
outline: solid 1px black;
}
.ladder-element-dark {
background-color: #131313;
}
.ladder-element-achieved {
background-color: rgba(50, 205, 50, 0.2);
}
.ladder-element-unachieved {
background-color: rgba(170, 85, 85, 0.2);
}
.instructions-list {
font-size: 1.2rem;
}
@@ -106,30 +28,6 @@
padding-bottom: 0.25rem;
}
.scoreinfo-grid-minimap {
display: grid;
grid-template-columns: repeat(auto-fill, 30px);
row-gap: 5px;
column-gap: 2px;
justify-items: center;
}
.scoreinfo-grid-minimap-element {
width: 20px;
height: 20px;
outline: 1px black solid;
display: flex;
justify-content: center;
align-content: center;
text-align: center;
color: white;
font-weight: 900;
}
.scoreinfo-grid-minimap-element-recent {
box-shadow: inset 0px 0px 5px goldenrod;
}
.privacy-policy > h2 {
margin-top: 1rem;
}
@@ -143,15 +41,6 @@
opacity: 0;
}
table {
border-width: $table-border-width;
border-style: solid;
}
.table.table-vertical-center th, .table.table-vertical-center td {
vertical-align: middle;
}
a:where(.MuiTab-root) {
@extend .transition-color;
&:hover {
@@ -1,8 +1,3 @@
body {
margin: 0;
padding: 0;
}
#splash-screen {
position: absolute;
z-index: 1000;
@@ -1,88 +0,0 @@
.timeline {
position: relative;
.timeline-bar {
position: absolute;
display: block;
width: 1px;
height: 100%;
background-color: var(--bs-gray-400);
z-index: 2;
}
.timeline-item {
display: flex;
align-items: center;
width: 100%;
justify-content: space-between;
border-radius: var(--bs-border-radius);
margin: 0 .5rem;
@include media-breakpoint-down(md) {
margin: .5rem 0;
padding: .5rem 0 !important;
position: relative;
}
&:after {
display: block;
width: 100%;
content: "";
position: absolute;
bottom: -.275rem;
border-bottom: 1px var(--bs-secondary) solid;
}
&.timeline-hover:hover {
background-color: var(--bs-secondary-bg);
}
.timeline-badge {
height: 0.75rem;
width: 0.75rem;
border-radius: 100%;
position: absolute;
z-index: 3;
@include media-breakpoint-down(md) {
transform: translateX(-0.35rem);
}
@include media-breakpoint-up(md) {
transform: translateX(-0.835rem);
}
}
.timeline-content {
display: flex;
flex-direction: column;
flex-wrap: wrap;
padding: 1rem 1rem;
width: 100%;
&-inner {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
@include media-breakpoint-down(md) {
flex-wrap: wrap;
flex-direction: column;
}
}
&-title {
text-align: left;
@include media-breakpoint-up(lg) {
width: 70%;
}
@include media-breakpoint-down(md) {
display: block;
align-self: start;
}
}
&-timestamp {
text-align: right;
@include media-breakpoint-down(md) {
align-self: end;
margin: .5rem 0;
}
}
}
}
}
+8
View File
@@ -0,0 +1,8 @@
@import "bootstrap";
@import "legacy";
@import "globals";
@import "themes";
@import "components";
@import "utilities";
@@ -1,8 +1,3 @@
code {
padding: #{$kbd-padding-y} #{$kbd-padding-x};
border-radius: var(--#{$prefix}border-radius-sm);
}
[data-bs-theme="light"] {
code {
background-color: $body-tertiary-bg;
+16
View File
@@ -0,0 +1,16 @@
@import "animations";
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
.focus-visible-ring:focus-visible {
outline: 0;
// By default, there is no `--bs-focus-ring-x`, `--bs-focus-ring-y`, or `--bs-focus-ring-blur`, but we provide CSS variables with fallbacks to initial `0` values
box-shadow: var(--#{$prefix}focus-ring-x, 0) var(--#{$prefix}focus-ring-y, 0) var(--#{$prefix}focus-ring-blur, 0) var(--#{$prefix}focus-ring-width) var(--#{$prefix}focus-ring-color);
}
@@ -1,9 +0,0 @@
@import "animations";
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}