Add Dark Mode for dialogs

This commit is contained in:
Justin Edmund 2022-12-06 18:38:36 -08:00
parent 0b021629d7
commit a2b30133d4
23 changed files with 322 additions and 280 deletions

View file

@ -0,0 +1,87 @@
.Dialog {
$multiplier: 4;
animation: 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0s 1 normal none running
openModal;
background: var(--dialog-bg);
border-radius: $card-corner;
display: flex;
flex-direction: column;
gap: $unit * $multiplier;
height: auto;
min-width: $unit * 48;
min-height: $unit * 12;
padding: $unit * $multiplier;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 21;
.DialogHeader {
display: flex;
align-items: center;
gap: $unit;
.left {
display: flex;
flex-direction: column;
flex-grow: 1;
gap: $unit;
p {
font-size: $font-small;
line-height: 1.25;
}
}
}
.DialogClose {
background: transparent;
&:hover {
cursor: pointer;
svg {
fill: $error;
}
}
svg {
fill: $grey-50;
float: right;
height: 24px;
width: 24px;
}
}
.DialogTitle {
color: var(--text-secondary);
font-size: $font-xlarge;
flex-grow: 1;
}
.DialogTop {
display: flex;
flex-direction: column;
flex-grow: 1;
gap: calc($unit / 2);
.SubTitle {
color: var(--text-secondary);
font-size: $font-small;
font-weight: $medium;
}
}
.DialogDescription {
color: var(--text-secondary);
flex-grow: 1;
}
.actions {
display: flex;
justify-content: flex-end;
width: 100%;
}
}

View file

@ -0,0 +1,39 @@
import React from 'react'
import * as DialogPrimitive from '@radix-ui/react-dialog'
import classNames from 'classnames'
import './index.scss'
interface Props
extends React.DetailedHTMLProps<
React.DialogHTMLAttributes<HTMLDivElement>,
HTMLDivElement
> {}
export const DialogContent = React.forwardRef<HTMLDivElement, Props>(
({ children, ...props }, forwardedRef) => {
const classes = classNames(
{
Dialog: true,
},
props.className
)
return (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay className="Overlay" />
<DialogPrimitive.Content
className={classes}
{...props}
ref={forwardedRef}
>
{children}
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
)
}
)
export const Dialog = DialogPrimitive.Root
export const DialogTrigger = DialogPrimitive.Trigger
export const DialogClose = DialogPrimitive.Close

View file

@ -1,31 +0,0 @@
.Fieldset {
border: none;
display: inline-flex;
flex-direction: column;
padding: 0;
margin: 0;
input {
-webkit-font-smoothing: antialiased;
background-color: var(--input-bg);
border: none;
border-radius: 6px;
box-sizing: border-box;
display: block;
padding: ($unit * 1.5) $unit-2x;
width: 100%;
}
.InputError {
color: $error;
font-size: $font-tiny;
margin: $unit 0;
padding: calc($unit / 2) ($unit * 2);
}
}
::placeholder {
/* Chrome, Firefox, Opera, Safari 10.1+ */
color: var(--text-tertiary) !important;
opacity: 1; /* Firefox */
}

View file

@ -1,40 +0,0 @@
import React from 'react'
import './index.scss'
interface Props {
fieldName: string
placeholder: string
value?: string
error: string
onBlur?: (event: React.ChangeEvent<HTMLInputElement>) => void
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
}
const Fieldset = React.forwardRef<HTMLInputElement, Props>(function fieldSet(
props,
ref
) {
const fieldType = ['password', 'confirm_password'].includes(props.fieldName)
? 'password'
: 'text'
return (
<fieldset className="Fieldset">
<input
autoComplete="off"
className="Input"
type={fieldType}
name={props.fieldName}
placeholder={props.placeholder}
defaultValue={props.value || ''}
onBlur={props.onBlur}
onChange={props.onChange}
ref={ref}
formNoValidate
/>
{props.error.length > 0 && <p className="InputError">{props.error}</p>}
</fieldset>
)
})
export default Fieldset

View file

@ -73,7 +73,7 @@
max-width: 258px; // Can we not do this?
&.empty {
color: var(--text-secondary);
color: var(--text-tertiary);
}
}

View file

@ -10,7 +10,7 @@
}
.MenuItem {
color: var(--text-secondary);
color: var(--text-tertiary);
font-weight: $normal;
&:hover:not(.disabled) {

View file

@ -0,0 +1,23 @@
.Input {
-webkit-font-smoothing: antialiased;
background-color: var(--input-bg);
border: none;
border-radius: 6px;
box-sizing: border-box;
display: block;
padding: ($unit * 1.5) $unit-2x;
width: 100%;
}
.InputError {
color: $error;
font-size: $font-tiny;
margin: $unit 0;
padding: calc($unit / 2) ($unit * 2);
}
::placeholder {
/* Chrome, Firefox, Opera, Safari 10.1+ */
color: var(--text-secondary) !important;
opacity: 1; /* Firefox */
}

View file

@ -0,0 +1,37 @@
import classNames from 'classnames'
import React from 'react'
import './index.scss'
interface Props
extends React.DetailedHTMLProps<
React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
> {
error?: string
label?: string
}
const Input = React.forwardRef<HTMLInputElement, Props>(
(props: Props, forwardedRef) => {
const classes = classNames({ Input: true }, props.className)
return (
<label className="Label" htmlFor={props.name}>
<input
{...props}
autoComplete="off"
className={classes}
defaultValue={props.value || ''}
ref={forwardedRef}
formNoValidate
/>
{props.label}
{props.error && props.error.length > 0 && (
<p className="InputError">{props.error}</p>
)}
</label>
)
}
)
export default Input

View file

@ -15,11 +15,11 @@
}
& p.placeholder {
color: var(--text-secondary-hover);
color: var(--text-tertiary-hover);
}
& svg {
fill: var(--icon-secondary-hover);
fill: var(--icon-tertiary-hover);
}
}
@ -48,7 +48,7 @@
color: var(--text-primary);
&.placeholder {
color: var(--text-secondary);
color: var(--text-tertiary);
}
}
}

View file

@ -10,7 +10,7 @@ import api from '~utils/api'
import { accountState } from '~utils/accountState'
import Button from '~components/Button'
import Fieldset from '~components/Fieldset'
import Fieldset from '~components/Input'
import CrossIcon from '~public/icons/Cross.svg'
import './index.scss'

View file

@ -90,7 +90,7 @@
color: var(--text-primary);
&.empty {
color: var(--text-tertiary);
color: var(--text-secondary);
}
}
}

View file

@ -1,33 +1,31 @@
.DropdownLabel {
align-items: center;
background: $grey-90;
background: var(--button-contained-bg);
border: none;
border-radius: $unit * 2;
color: $grey-50;
border-radius: $unit-2x;
color: var(--text-secondary);
display: flex;
gap: calc($unit / 2);
gap: $unit-half;
flex-direction: row;
padding: ($unit) ($unit * 2);
padding: $unit ($unit * 1.5) $unit $unit-2x;
&:hover {
background: $grey-80;
color: $grey-15;
background: var(--button-contained-bg-hover);
color: var(--text-primary);
cursor: pointer;
}
.count {
color: $grey-60;
color: var(--text-tertiary);
font-weight: $medium;
}
& > .icon {
$diameter: 12px;
$diameter: 16px;
height: $diameter;
width: $diameter;
svg {
transform: scale(0.85);
path {
fill: $grey-60;
}
@ -36,12 +34,11 @@
}
.Dropdown {
background: $grey-100;
background: var(--button-contained-bg);
border-radius: $unit;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.18);
display: flex;
flex-direction: column;
gap: calc($unit / 2);
padding: $unit;
min-width: 120px;
@ -49,7 +46,7 @@
overflow: hidden;
svg {
fill: $grey-100;
fill: var(--button-contained-bg);
filter: drop-shadow(0px 0px 1px rgb(0 0 0 / 0.18));
}
}
@ -66,9 +63,9 @@
}
.Label {
color: $grey-60;
color: var(--text-tertiary);
font-size: $font-small;
margin-bottom: calc($unit / 2);
padding-left: calc($unit / 2);
margin-bottom: $unit-half;
padding: $unit-half 0 $unit $unit-half;
}
}

View file

@ -1,29 +1,30 @@
.Item {
align-items: center;
border-radius: calc($unit / 2);
color: $grey-50;
color: var(--text-secondary);
font-size: $font-regular;
line-height: 1.2;
min-width: 100px;
position: relative;
padding: $unit;
padding-left: $unit * 3;
padding-left: $unit * 3.5;
&:hover {
background: $grey-90;
background: var(--button-contained-bg-hover);
color: var(--text-primary);
cursor: pointer;
}
&[data-state='checked'] {
background: $grey-90;
background: var(--button-contained-bg-hover);
svg {
fill: $grey-55;
fill: var(--text-secondary);
}
}
.Indicator {
$diameter: 18px;
$diameter: 20px;
display: flex;
align-items: center;

View file

@ -39,16 +39,16 @@
label {
width: 100%;
.Input {
background: $grey-90;
border: none;
border-radius: calc($unit / 2);
box-sizing: border-box;
font-size: $font-regular;
padding: $unit * 1.5;
text-align: left;
width: 100%;
}
// .Input {
// background: $grey-90;
// border: none;
// border-radius: calc($unit / 2);
// box-sizing: border-box;
// font-size: $font-regular;
// padding: $unit * 1.5;
// text-align: left;
// width: 100%;
// }
}
}
}
@ -62,17 +62,17 @@
h5.total {
font-size: $font-regular;
font-weight: $normal;
color: $grey-50;
padding: calc($unit / 2) ($unit * 1.5);
color: var(--text-tertiary);
padding: $unit-half ($unit * 1.5);
}
.footer {
align-items: center;
display: flex;
color: $grey-60;
color: var(--text-tertiary);
font-size: $font-regular;
font-weight: $normal;
height: $unit * 10;
height: $unit-10x;
justify-content: center;
}
@ -91,8 +91,8 @@
}
.Search.Dialog #NoResults h2 {
color: #ccc;
color: var(--text-secondary);
font-size: $font-large;
font-weight: 500;
margin-top: -32px;
margin-top: $unit-4x * -1;
}

View file

@ -6,8 +6,14 @@ import InfiniteScroll from 'react-infinite-scroll-component'
import api from '~utils/api'
import * as Dialog from '@radix-ui/react-dialog'
import {
Dialog,
DialogTrigger,
DialogContent,
DialogClose,
} from '~components/Dialog'
import Input from '~components/Input'
import CharacterSearchFilterBar from '~components/CharacterSearchFilterBar'
import WeaponSearchFilterBar from '~components/WeaponSearchFilterBar'
import SummonSearchFilterBar from '~components/SummonSearchFilterBar'
@ -317,61 +323,54 @@ const SearchModal = (props: Props) => {
}
return (
<Dialog.Root open={open} onOpenChange={openChange}>
<Dialog.Trigger asChild>{props.children}</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Content className="Search Dialog">
<div id="Header">
<div id="Bar">
<label className="search_label" htmlFor="search_input">
<input
autoComplete="off"
type="text"
name="query"
className="Input"
id="search_input"
ref={searchInput}
value={query}
placeholder={props.placeholderText}
onChange={inputChanged}
/>
</label>
<Dialog.Close className="DialogClose" onClick={openChange}>
<CrossIcon />
</Dialog.Close>
</div>
{props.object === 'characters' ? (
<CharacterSearchFilterBar sendFilters={receiveFilters} />
) : (
''
)}
{props.object === 'weapons' ? (
<WeaponSearchFilterBar sendFilters={receiveFilters} />
) : (
''
)}
{props.object === 'summons' ? (
<SummonSearchFilterBar sendFilters={receiveFilters} />
) : (
''
)}
{props.object === 'job_skills' ? (
<JobSkillSearchFilterBar sendFilters={receiveFilters} />
) : (
''
)}
<Dialog open={open} onOpenChange={openChange}>
<DialogTrigger asChild>{props.children}</DialogTrigger>
<DialogContent className="Search Dialog">
<div id="Header">
<div id="Bar">
<Input
autoComplete="off"
className="Search"
name="query"
placeholder={props.placeholderText}
ref={searchInput}
value={query}
onChange={inputChanged}
/>
<DialogClose className="DialogClose" onClick={openChange}>
<CrossIcon />
</DialogClose>
</div>
{props.object === 'characters' ? (
<CharacterSearchFilterBar sendFilters={receiveFilters} />
) : (
''
)}
{props.object === 'weapons' ? (
<WeaponSearchFilterBar sendFilters={receiveFilters} />
) : (
''
)}
{props.object === 'summons' ? (
<SummonSearchFilterBar sendFilters={receiveFilters} />
) : (
''
)}
{props.object === 'job_skills' ? (
<JobSkillSearchFilterBar sendFilters={receiveFilters} />
) : (
''
)}
</div>
<div id="Results" ref={scrollContainer}>
<h5 className="total">
{t('search.result_count', { record_count: recordCount })}
</h5>
{open ? renderResults() : ''}
</div>
</Dialog.Content>
<Dialog.Overlay className="Overlay" />
</Dialog.Portal>
</Dialog.Root>
<div id="Results" ref={scrollContainer}>
<h5 className="total">
{t('search.result_count', { record_count: recordCount })}
</h5>
{open ? renderResults() : ''}
</div>
</DialogContent>
</Dialog>
)
}

View file

@ -12,7 +12,7 @@
}
&[data-placeholder] > span:not(.SelectIcon) {
color: var(--text-tertiary);
color: var(--text-secondary);
}
& > span:not(.SelectIcon) {

View file

@ -1,12 +1,13 @@
.SelectItem {
border-radius: $item-corner;
border: 2px solid transparent;
color: var(--text-primary);
color: var(--text-secondary);
font-size: $font-regular;
padding: ($unit * 1.5) $unit-2x;
&:hover {
background-color: var(--option-bg-hover);
color: var(--text-primary);
cursor: pointer;
outline: none;
}

View file

@ -11,7 +11,7 @@ import api from '~utils/api'
import { accountState } from '~utils/accountState'
import Button from '~components/Button'
import Fieldset from '~components/Fieldset'
import Fieldset from '~components/Input'
import CrossIcon from '~public/icons/Cross.svg'
import './index.scss'

View file

@ -137,6 +137,7 @@ const TopHeader = () => {
return (
<Button
accessoryIcon={<SaveIcon />}
blended={true}
text="Saved"
onClick={toggleFavorite}
/>
@ -145,6 +146,7 @@ const TopHeader = () => {
return (
<Button
accessoryIcon={<SaveIcon />}
blended={true}
text="Save"
onClick={toggleFavorite}
/>

View file

@ -5,8 +5,12 @@
padding: $unit * 1.5;
&:hover {
background: $grey-90;
background: var(--button-contained-bg);
cursor: pointer;
.Info h5 {
color: var(--text-primary);
}
}
img {
@ -24,7 +28,7 @@
gap: calc($unit / 2);
h5 {
color: #555;
color: var(--text-secondary);
display: inline-block;
font-size: $font-medium;
font-weight: $medium;

View file

@ -124,93 +124,6 @@ select {
z-index: 20;
}
.Dialog {
$multiplier: 4;
animation: 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0s 1 normal none running
openModal;
background: $grey-100;
border-radius: $unit;
display: flex;
flex-direction: column;
gap: $unit * $multiplier;
height: auto;
min-width: $unit * 48;
min-height: $unit * 12;
padding: $unit * $multiplier;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 21;
.DialogHeader {
display: flex;
align-items: center;
gap: $unit;
.left {
display: flex;
flex-direction: column;
flex-grow: 1;
gap: $unit;
p {
color: $grey-50;
font-size: $font-small;
line-height: 1.25;
}
}
}
.DialogClose {
background: transparent;
&:hover {
cursor: pointer;
svg {
fill: $error;
}
}
svg {
fill: $grey-50;
float: right;
height: 24px;
width: 24px;
}
}
.DialogTitle {
font-size: $font-xlarge;
flex-grow: 1;
}
.DialogTop {
display: flex;
flex-direction: column;
flex-grow: 1;
gap: calc($unit / 2);
.SubTitle {
color: $grey-55;
font-size: $font-small;
font-weight: $medium;
}
}
.DialogDescription {
flex-grow: 1;
}
.actions {
display: flex;
justify-content: flex-end;
width: 100%;
}
}
.Hovercard {
background: #222;
border-radius: $unit;

View file

@ -7,6 +7,9 @@
--card-bg: #{$grey-100};
--bar-bg: #{$grey-100};
// Light - Menus
--dialog-bg: #{$dialog--bg--light};
// Light - Menus
--menu-bg: #{$menu--bg--light};
--menu-separator: #{$menu--separator--light};
@ -40,11 +43,10 @@
// Light - Text
--text-primary: #{$text--primary--color--light};
--text-secondary: #{$text--secondary--color--light};
--text-secondary-hover: #{$text--secondary--hover--light};
--text-tertiary: #{$text--tertiary--color--light};
--text-tertiary-hover: #{$text--tertiary--hover--light};
// Light - Icons
--icon-secondary: #{$icon--secondary--color--light};
@ -54,8 +56,6 @@
--tag-bg: #{$tag--bg--light};
--tag-text: #{$tag--text--light};
--switch-nub: #{$switch--nub--bg--light};
// Light - Extra Weapons
--extra-purple-bg: #{$extra--purple--bg--light};
--extra-purple-card-bg: #{$extra--purple--card--bg--light};
@ -63,6 +63,8 @@
--extra-purple-secondary: #{$extra--purple--secondary--light};
--extra-purple-text: #{$extra--purple--text--light};
--switch-nub: #{$switch--nub--bg--light};
// Light - Subaura Summons
--subaura-orange-bg: #{$subaura--orange--bg--light};
--subaura-orange-card-bg: #{$subaura--orange--card--bg--light};
@ -95,6 +97,9 @@
--card-bg: #{$page--element--bg--dark};
--bar-bg: #{$grey-10};
// Dark - Dialogs
--dialog-bg: #{$dialog--bg--dark};
// Dark - Menus
--menu-bg: #{$menu--bg--dark};
--menu-text: #{$menu--text--dark};
@ -128,11 +133,10 @@
// Dark - Text
--text-primary: #{$text--primary--color--dark};
--text-secondary: #{$text--secondary--color--dark};
--text-secondary-hover: #{$text--secondary--hover--dark};
--text-tertiary: #{$text--tertiary--color--dark};
--text-tertiary-hover: #{$text--tertiary--hover--dark};
// Dark - Icons
--icon-secondary: #{$icon--secondary--color--dark};
@ -142,8 +146,6 @@
--tag-bg: #{$tag--bg--dark};
--tag-text: #{$tag--text--dark};
--switch-nub: #{$switch--nub--bg--dark};
// Dark - Extra Weapons
--extra-purple-bg: #{$extra--purple--bg--dark};
--extra-purple-card-bg: #{$extra--purple--card--bg--dark};
@ -151,6 +153,8 @@
--extra-purple-secondary: #{$extra--purple--secondary--dark};
--extra-purple-text: #{$extra--purple--text--dark};
--switch-nub: #{$switch--nub--bg--dark};
// Dark - Subaura Summons
--subaura-orange-bg: #{$subaura--orange--bg--dark};
--subaura-orange-card-bg: #{$subaura--orange--card--bg--dark};

View file

@ -113,6 +113,10 @@ $page--hover--dark: $grey-30;
$page--element--bg--light: $grey-70;
$page--element--bg--dark: $grey-40;
// Color Definitions: Dialog
$dialog--bg--light: $grey-100;
$dialog--bg--dark: $grey-25;
// Color Definitions: Menu
$menu--bg--light: $grey-100;
$menu--bg--dark: $grey-05;
@ -158,13 +162,13 @@ $input--bound--bg--dark--hover: $grey-25;
// Color Definitions: Select
$select--bg--light: $grey-100;
$select--bg--dark: $grey-05;
$select--bg--dark: $grey-10;
$select--contained--bg--light: $grey-90;
$select--contained--bg--dark: $grey-05;
$select--contained--bg--light--hover: $grey-80;
$select--contained--bg--dark--hover: $grey-00;
$select--separator--light: $grey-90;
$select--separator--dark: $grey-00;
$select--separator--dark: $grey-05;
$option--bg--light--hover: $grey-90;
$option--bg--dark--hover: $grey-00;
@ -205,10 +209,14 @@ $subaura--orange--text--dark: $orange-00;
$text--primary--color--light: $grey-40;
$text--primary--color--dark: $grey-90;
$text--secondary--color--light: $grey-50;
$text--secondary--hover--light: $grey-40;
$text--secondary--color--dark: $grey-50;
$text--secondary--hover--dark: $grey-70;
$text--secondary--color--light: $grey-60;
$text--secondary--color--dark: $grey-60;
$text--tertiary--color--light: $grey-50;
$text--tertiary--color--dark: $grey-50;
$text--tertiary--hover--light: $grey-40;
$text--tertiary--hover--dark: $grey-70;
// Color Definitions: Icon
$icon--secondary--color--light: $grey-70;
@ -216,9 +224,6 @@ $icon--secondary--color--dark: $grey-50;
$icon--secondary--hover--light: $grey-50;
$icon--secondary--hover--dark: $grey-70;
$text--tertiary--color--light: $grey-60;
$text--tertiary--color--dark: $grey-60;
// Color Definitions: Tag
$tag--bg--light: $grey-60;
$tag--bg--dark: $grey-00;
@ -245,6 +250,7 @@ $scale-wide: scale(1.05, 1.05);
$scale-tall: scale(1.012, 1.012);
// Border radius
$card-corner: $unit * 1.5;
$input-corner: $unit;
$item-corner: $unit-half;