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 }) => (
<>
-
+
+
+
*,