From 2daf868f686349721b5ea32b15ba135f0fc816a7 Mon Sep 17 00:00:00 2001 From: Thien Do <5953369+thien-do@users.noreply.github.com> Date: Thu, 11 Aug 2022 13:39:46 +0700 Subject: [PATCH] feat: Improve settings styling --- src/web/focus/focus.ts | 3 -- .../outline.module.css} | 11 +++-- src/web/outline/outline.ts | 7 ++++ src/web/range/range.module.scss | 2 +- src/web/range/range.tsx | 4 +- src/web/settings/radio/option.module.css | 4 ++ src/web/settings/radio/option.tsx | 23 +++++------ src/web/settings/switch/switch.module.css | 5 +++ src/web/settings/switch/switch.tsx | 22 ++++++++++ src/web/settings/vim.tsx | 20 ++++------ src/web/switch/switch.module.css | 40 +++++++++++++++++++ src/web/switch/switch.tsx | 31 ++++++++++++++ src/web/toolbar/button/button.module.css | 4 ++ src/web/toolbar/button/button.tsx | 35 ++++++++-------- src/web/toolbar/settings/settings.tsx | 12 +++--- src/web/toolbar/toolbar.module.css | 5 +-- 16 files changed, 163 insertions(+), 65 deletions(-) delete mode 100644 src/web/focus/focus.ts rename src/web/{focus/focus.module.css => outline/outline.module.css} (54%) create mode 100644 src/web/outline/outline.ts create mode 100644 src/web/settings/switch/switch.module.css create mode 100644 src/web/settings/switch/switch.tsx create mode 100644 src/web/switch/switch.module.css create mode 100644 src/web/switch/switch.tsx diff --git a/src/web/focus/focus.ts b/src/web/focus/focus.ts deleted file mode 100644 index 5e90cb6..0000000 --- a/src/web/focus/focus.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as s from "./focus.module.css"; - -export const focusStyle = s.focus; diff --git a/src/web/focus/focus.module.css b/src/web/outline/outline.module.css similarity index 54% rename from src/web/focus/focus.module.css rename to src/web/outline/outline.module.css index 3f2a74b..fc1a5dd 100644 --- a/src/web/focus/focus.module.css +++ b/src/web/outline/outline.module.css @@ -1,12 +1,15 @@ -.focus { +.onActive, +.onFocus { transition: outline 300ms var(--ease); } -.focus, -.focus:focus { +.onActive, +.onFocus, +.onFocus:focus { outline: solid 8px transparent; } -.focus:focus-visible { +.onActive.active, +.onFocus:focus-visible { outline: solid 2px var(--color-rose); } diff --git a/src/web/outline/outline.ts b/src/web/outline/outline.ts new file mode 100644 index 0000000..d797fc7 --- /dev/null +++ b/src/web/outline/outline.ts @@ -0,0 +1,7 @@ +import * as s from "./outline.module.css"; + +export const outline = { + onFocus: s.onFocus, + onActive: s.onActive, + active: s.active, +}; diff --git a/src/web/range/range.module.scss b/src/web/range/range.module.scss index d367928..4094f4b 100644 --- a/src/web/range/range.module.scss +++ b/src/web/range/range.module.scss @@ -11,7 +11,7 @@ appearance: none; border: none; - background-color: var(--color-muted); + background-color: var(--color-subtle); height: 20px; width: 8px; border-radius: 8px; diff --git a/src/web/range/range.tsx b/src/web/range/range.tsx index bad0cfe..31fa1e3 100644 --- a/src/web/range/range.tsx +++ b/src/web/range/range.tsx @@ -1,5 +1,5 @@ import { CSSProperties } from "react"; -import { focusStyle } from "../focus/focus"; +import { outline } from "../outline/outline"; import * as s from "./range.module.scss"; type Props = JSX.IntrinsicElements["input"] & { @@ -23,7 +23,7 @@ export const Range = (props: Props): JSX.Element => { ); diff --git a/src/web/settings/radio/option.module.css b/src/web/settings/radio/option.module.css index 9a498dc..47df1b9 100644 --- a/src/web/settings/radio/option.module.css +++ b/src/web/settings/radio/option.module.css @@ -7,6 +7,10 @@ border-radius: 6px; } +.container:active { + background-color: var(--color-highlightMed); +} + .label { text-align: center; font-size: 12px; diff --git a/src/web/settings/radio/option.tsx b/src/web/settings/radio/option.tsx index 8795b9a..6d8ca1a 100644 --- a/src/web/settings/radio/option.tsx +++ b/src/web/settings/radio/option.tsx @@ -1,4 +1,5 @@ import { RadioGroup } from "@headlessui/react"; +import { outline } from "../../outline/outline"; import * as s from "./option.module.css"; interface Props { @@ -7,24 +8,18 @@ interface Props { value: unknown; } -// https://github.com/tailwindlabs/headlessui/discussions/1743 -interface OptionRenderPropArg { - checked: boolean; - active: boolean; - disabled: boolean; -} - export const SettingsRadioOption = (props: Props): JSX.Element => { const { icon, label, value } = props; - const body = ({ checked }: OptionRenderPropArg) => ( -
+ return ( + + value={value} + className={({ checked }) => + [s.container, checked ? s.selected : "", outline.onFocus].join(" ") + } + >
{icon}
{label}
-
- ); - - return ( - value={value}>{body} + ); }; diff --git a/src/web/settings/switch/switch.module.css b/src/web/settings/switch/switch.module.css new file mode 100644 index 0000000..60c4c87 --- /dev/null +++ b/src/web/settings/switch/switch.module.css @@ -0,0 +1,5 @@ +.container { + display: flex; + justify-content: space-between; + align-items: center; +} diff --git a/src/web/settings/switch/switch.tsx b/src/web/settings/switch/switch.tsx new file mode 100644 index 0000000..2cee8b8 --- /dev/null +++ b/src/web/settings/switch/switch.tsx @@ -0,0 +1,22 @@ +import { Switch } from "@headlessui/react"; +import { SwitchButton } from "../../switch/switch"; +import s from "./switch.module.css"; + +interface Props { + checked: boolean; + setChecked: (checked: boolean) => void; + label: string; +} + +export const SettingsSwitch = (props: Props): JSX.Element => { + const { checked, setChecked, label } = props; + return ( + + {/* Switch.Group is not a real element and cannot have className */} +
+ {label} + +
+
+ ); +}; diff --git a/src/web/settings/vim.tsx b/src/web/settings/vim.tsx index 3ec1f2d..e7c4c12 100644 --- a/src/web/settings/vim.tsx +++ b/src/web/settings/vim.tsx @@ -1,21 +1,17 @@ +import { SettingsSwitch } from "./switch/switch"; import { SettingsState } from "./type"; -import { Switch } from "@headlessui/react"; interface Props extends SettingsState {} export const SettingsVim = (props: Props): JSX.Element => { const { setSettings, settings } = props; return ( - - Vim mode - { - setSettings((prev) => ({ ...prev, vim: checked })); - }} - > - {settings.vim ? "yes" : "no"} - - + { + setSettings((prev) => ({ ...prev, vim: checked })); + }} + /> ); }; diff --git a/src/web/switch/switch.module.css b/src/web/switch/switch.module.css new file mode 100644 index 0000000..bd42c70 --- /dev/null +++ b/src/web/switch/switch.module.css @@ -0,0 +1,40 @@ +.container { + display: flex; + position: relative; + + appearance: none; + background-color: var(--color-overlay); + border: none; + border-radius: 999px; + padding: 3px; +} + +.container:active { + background-color: var(--color-highlightMed); +} + +.icon { + flex: 0 0 auto; +} + +.icon svg { + display: block !important; + transform: scale(0.75); +} + +.thumb { + width: 18px; + height: 18px; + border-radius: 20px; + background-color: var(--color-subtle); + + position: absolute; + top: 2px; + left: 2px; + + transition: transform 200ms var(--ease); +} + +.active .thumb { + transform: translateX(16px); +} diff --git a/src/web/switch/switch.tsx b/src/web/switch/switch.tsx new file mode 100644 index 0000000..1a167f2 --- /dev/null +++ b/src/web/switch/switch.tsx @@ -0,0 +1,31 @@ +import { Switch } from "@headlessui/react"; +import { XIcon, CheckIcon } from "@primer/octicons-react"; +import { outline } from "../outline/outline"; +import * as s from "./switch.module.css"; + +interface Props { + checked: boolean; + setChecked: (checked: boolean) => void; +} + +export const SwitchButton = (props: Props): JSX.Element => { + const { checked, setChecked } = props; + + return ( + + + + + + + + + + ); +}; diff --git a/src/web/toolbar/button/button.module.css b/src/web/toolbar/button/button.module.css index ed17625..7980eaf 100644 --- a/src/web/toolbar/button/button.module.css +++ b/src/web/toolbar/button/button.module.css @@ -11,6 +11,10 @@ background-color: var(--color-overlay); } +.button:active { + background-color: var(--color-highlightMed); +} + .button.selected { color: var(--color-text); } diff --git a/src/web/toolbar/button/button.tsx b/src/web/toolbar/button/button.tsx index 08e66d4..dad1f3e 100644 --- a/src/web/toolbar/button/button.tsx +++ b/src/web/toolbar/button/button.tsx @@ -1,28 +1,25 @@ import { Icon } from "@primer/octicons-react"; -import { ButtonHTMLAttributes, ElementType, forwardRef } from "react"; -import { focusStyle } from "../../focus/focus"; +import { ButtonHTMLAttributes } from "react"; +import { outline } from "../../outline/outline"; import * as s from "./button.module.css"; interface Props extends ButtonHTMLAttributes { Icon: Icon; label: string; selected?: boolean; - as?: ElementType; } -export const ToolbarButton = forwardRef( - (props, ref): JSX.Element => { - const { Icon, label, selected, as, ...rest } = props; - const Button = as ?? "button"; - return ( - - ); - } -); +export const ToolbarButton = (props: Props): JSX.Element => { + const { Icon, label, selected, ...rest } = props; + return ( + + ); +}; diff --git a/src/web/toolbar/settings/settings.tsx b/src/web/toolbar/settings/settings.tsx index f8fb24d..7969443 100644 --- a/src/web/toolbar/settings/settings.tsx +++ b/src/web/toolbar/settings/settings.tsx @@ -1,7 +1,9 @@ import { shift, useFloating } from "@floating-ui/react-dom"; import { Popover } from "@headlessui/react"; import { GearIcon } from "@primer/octicons-react"; +import { Fragment } from "react"; import { LayoutState } from "../../layout/type"; +import { outline } from "../../outline/outline"; import { SettingsPanel } from "../../settings/panel"; import { SettingsState } from "../../settings/type"; import { ToolbarButton } from "./../button/button"; @@ -15,13 +17,9 @@ export const ToolbarSettings = (props: Props): JSX.Element => { {({ open }) => ( <> - + + + *,