Skip to content

Commit

Permalink
feat: Improve settings styling
Browse files Browse the repository at this point in the history
  • Loading branch information
thien-do committed Aug 11, 2022
1 parent 1df5b25 commit 2daf868
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 65 deletions.
3 changes: 0 additions & 3 deletions src/web/focus/focus.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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);
}
7 changes: 7 additions & 0 deletions src/web/outline/outline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as s from "./outline.module.css";

export const outline = {
onFocus: s.onFocus,
onActive: s.onActive,
active: s.active,
};
2 changes: 1 addition & 1 deletion src/web/range/range.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/web/range/range.tsx
Original file line number Diff line number Diff line change
@@ -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"] & {
Expand All @@ -23,7 +23,7 @@ export const Range = (props: Props): JSX.Element => {
<input
{...native}
type="range"
className={[s.range, focusStyle].join(" ")}
className={[s.range, outline.onFocus].join(" ")}
style={getCss(props)}
/>
);
Expand Down
4 changes: 4 additions & 0 deletions src/web/settings/radio/option.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
border-radius: 6px;
}

.container:active {
background-color: var(--color-highlightMed);
}

.label {
text-align: center;
font-size: 12px;
Expand Down
23 changes: 9 additions & 14 deletions src/web/settings/radio/option.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { RadioGroup } from "@headlessui/react";
import { outline } from "../../outline/outline";
import * as s from "./option.module.css";

interface Props {
Expand All @@ -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) => (
<div className={[s.container, checked ? s.selected : ""].join(" ")}>
return (
<RadioGroup.Option<"div", unknown>
value={value}
className={({ checked }) =>
[s.container, checked ? s.selected : "", outline.onFocus].join(" ")
}
>
<div className={s.icon}>{icon}</div>
<div className={s.label}>{label}</div>
</div>
);

return (
<RadioGroup.Option<"div", unknown> value={value}>{body}</RadioGroup.Option>
</RadioGroup.Option>
);
};
5 changes: 5 additions & 0 deletions src/web/settings/switch/switch.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.container {
display: flex;
justify-content: space-between;
align-items: center;
}
22 changes: 22 additions & 0 deletions src/web/settings/switch/switch.tsx
Original file line number Diff line number Diff line change
@@ -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>
{/* Switch.Group is not a real element and cannot have className */}
<div className={s.container}>
<Switch.Label>{label}</Switch.Label>
<SwitchButton checked={checked} setChecked={setChecked} />
</div>
</Switch.Group>
);
};
20 changes: 8 additions & 12 deletions src/web/settings/vim.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Switch.Group>
<Switch.Label>Vim mode</Switch.Label>
<Switch
checked={settings.vim}
onChange={(checked) => {
setSettings((prev) => ({ ...prev, vim: checked }));
}}
>
<span>{settings.vim ? "yes" : "no"}</span>
</Switch>
</Switch.Group>
<SettingsSwitch
label="Vim mode"
checked={settings.vim}
setChecked={(checked) => {
setSettings((prev) => ({ ...prev, vim: checked }));
}}
/>
);
};
40 changes: 40 additions & 0 deletions src/web/switch/switch.module.css
Original file line number Diff line number Diff line change
@@ -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);
}
31 changes: 31 additions & 0 deletions src/web/switch/switch.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Switch
checked={checked}
onChange={setChecked}
className={[s.container, checked ? s.active : "", outline.onFocus].join(
" "
)}
>
<span aria-hidden className={s.icon}>
<CheckIcon size={16} />
</span>
<span aria-hidden className={s.icon}>
<XIcon size={16} />
</span>
<span aria-hidden className={s.thumb} />
</Switch>
);
};
4 changes: 4 additions & 0 deletions src/web/toolbar/button/button.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
background-color: var(--color-overlay);
}

.button:active {
background-color: var(--color-highlightMed);
}

.button.selected {
color: var(--color-text);
}
Expand Down
35 changes: 16 additions & 19 deletions src/web/toolbar/button/button.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLButtonElement> {
Icon: Icon;
label: string;
selected?: boolean;
as?: ElementType;
}

export const ToolbarButton = forwardRef<HTMLElement, Props>(
(props, ref): JSX.Element => {
const { Icon, label, selected, as, ...rest } = props;
const Button = as ?? "button";
return (
<Button
{...rest}
type="button"
className={[s.button, selected ? s.selected : "", focusStyle].join(" ")}
ref={ref}
>
<Icon size={16} aria-label={label} />
</Button>
);
}
);
export const ToolbarButton = (props: Props): JSX.Element => {
const { Icon, label, selected, ...rest } = props;
return (
<button
{...rest}
type="button"
className={[s.button, selected ? s.selected : "", outline.onFocus].join(
" "
)}
>
<Icon size={16} aria-label={label} />
</button>
);
};
12 changes: 5 additions & 7 deletions src/web/toolbar/settings/settings.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -15,13 +17,9 @@ export const ToolbarSettings = (props: Props): JSX.Element => {
<Popover>
{({ open }) => (
<>
<ToolbarButton
ref={float.reference}
as={Popover.Button}
Icon={GearIcon}
label="Settings"
selected={open}
/>
<Popover.Button ref={float.reference} as="div">
<ToolbarButton Icon={GearIcon} label="Settings" selected={open} />
</Popover.Button>
<Popover.Panel
ref={float.floating}
style={{
Expand Down
5 changes: 2 additions & 3 deletions src/web/toolbar/toolbar.module.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
.container {
display: flex;
align-items: center;
padding: 0px 16px;
/* Mac's toolbar height */
height: 52px;

Expand All @@ -18,8 +17,8 @@
align-items: center;
gap: 8px;

/* Vertical padding for outline to be visible */
padding: 8px 0;
/* Padding for outline to be visible */
padding: 8px 16px;
}

.left > *,
Expand Down

0 comments on commit 2daf868

Please sign in to comment.