Skip to content

Commit

Permalink
feat: Dynamic popover panel height
Browse files Browse the repository at this point in the history
  • Loading branch information
thien-do committed Aug 11, 2022
1 parent 2daf868 commit 92e7bab
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 34 deletions.
3 changes: 3 additions & 0 deletions src/web/range/range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ type Props = JSX.IntrinsicElements["input"] & {
step: number;
min: number;
max: number;
value: number;
};

export type { Props as RangeProps };

const getCss = (props: Props): CSSProperties => {
const { min, max, step } = props;
const steps = (max - min) / step;
Expand Down
31 changes: 18 additions & 13 deletions src/web/settings/font-size.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { EDITOR_TYPOGRAPHY_OPTIONS } from "../editor/input/typography";
import { Range } from "../range/range";
import { SettingsRange } from "./range/range";
import { TypographyIcon } from "@primer/octicons-react";
import { SettingsState } from "./type";

interface Props extends SettingsState {}
Expand All @@ -9,22 +10,26 @@ const SIZES: number[] = [...EDITOR_TYPOGRAPHY_OPTIONS.keys()];
export const SettingsFontSize = (props: Props): JSX.Element => {
const { setSettings, settings } = props;
return (
<label>
<span>Text size</span>
<span>{settings.fontSize}</span>
<Range
min={0}
max={SIZES.length - 1}
step={1}
value={SIZES.indexOf(settings.fontSize)}
onChange={(event) => {
<SettingsRange
label="Text size"
value={`${settings.fontSize} px`}
input={{
min: 0,
max: SIZES.length - 1,
step: 1,
onChange: (event) => {
const index = event.currentTarget.valueAsNumber;
const value = SIZES.at(index);
if (value === undefined) console.warn(`Unknown index "${index}"`);
const fontSize = value ?? 20;
setSettings((prev) => ({ ...prev, fontSize }));
}}
/>
</label>
},
value: SIZES.indexOf(settings.fontSize),
}}
icons={{
left: <TypographyIcon size={16} />,
right: <TypographyIcon size={24} />,
}}
/>
);
};
3 changes: 2 additions & 1 deletion src/web/settings/panel.module.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
.wrapper {
/* Reliable offset to anchor and screen */
padding: 6px;
height: 100%;
}

.container {
width: 320px;
max-height: 70vh;
overflow: auto;
height: 100%;

padding: 18px;
/* inner radius + padding / 2 */
Expand Down
38 changes: 38 additions & 0 deletions src/web/settings/range/range.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.container {
display: flex;
flex-direction: column;
gap: 6px;
}

.header {
display: flex;
justify-content: space-between;
}

.label {
flex: 0 0 auto;
}

.value {
font-variant-numeric: tabular-nums;
color: var(--color-subtle);
}

.control {
display: flex;
align-items: center;
gap: 12px;
}

.icon {
flex: 0 0 auto;
color: var(--color-subtle);
}

.icon svg {
display: block !important;
}

.input {
flex: 1 1 0px;
}
32 changes: 32 additions & 0 deletions src/web/settings/range/range.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Icon } from "@primer/octicons-react";
import { Range, RangeProps } from "../../range/range";
import * as s from "./range.module.css";

interface Props {
input: RangeProps;
label: string;
value: string;
icons: {
left: JSX.Element;
right: JSX.Element;
};
}

export const SettingsRange = (props: Props): JSX.Element => {
const { input, label, icons, value } = props;
return (
<label className={s.container}>
<span className={s.header}>
<span className={s.label}>{label}</span>
<span className={s.value}>{value}</span>
</span>
<span className={s.control}>
<span className={s.icon}>{icons.left}</span>
<span className={s.input}>
<Range {...input} />
</span>
<span className={s.icon}>{icons.right}</span>
</span>
</label>
);
};
30 changes: 18 additions & 12 deletions src/web/settings/wrap-column.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ArrowBothIcon } from "@primer/octicons-react";
import { Range } from "../range/range";
import { SettingsRange } from "./range/range";
import { SettingsState } from "./type";

interface Props extends SettingsState {}
Expand All @@ -8,22 +10,26 @@ const COLUMNS = [64, 72, 80, 100, 120];
export const SettingsWrapColumn = (props: Props): JSX.Element => {
const { setSettings, settings } = props;
return (
<label>
<span>Line length</span>
<span>{settings.wrapColumn}</span>
<Range
min={0}
max={COLUMNS.length - 1}
step={1}
value={COLUMNS.indexOf(settings.wrapColumn)}
onChange={(event) => {
<SettingsRange
label="Line length"
value={`${settings.wrapColumn} characters`}
input={{
min: 0,
max: COLUMNS.length - 1,
step: 1,
onChange: (event) => {
const index = event.currentTarget.valueAsNumber;
const value = COLUMNS.at(index);
if (value === undefined) console.warn(`Unknown index "${index}"`);
const wrapColumn = value ?? 80;
setSettings((prev) => ({ ...prev, wrapColumn }));
}}
/>
</label>
},
value: COLUMNS.indexOf(settings.wrapColumn),
}}
icons={{
left: <ArrowBothIcon size={16} />,
right: <ArrowBothIcon size={24} />,
}}
/>
);
};
6 changes: 5 additions & 1 deletion src/web/switch/switch.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@

.icon {
flex: 0 0 auto;
padding: 2px;
}

.icon svg {
display: block !important;
transform: scale(0.75);
}

.on {
transform: rotate(90deg);
}

.thumb {
Expand Down
10 changes: 5 additions & 5 deletions src/web/switch/switch.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Switch } from "@headlessui/react";
import { XIcon, CheckIcon } from "@primer/octicons-react";
import { DashIcon, DotIcon } from "@primer/octicons-react";
import { outline } from "../outline/outline";
import * as s from "./switch.module.css";

Expand All @@ -19,11 +19,11 @@ export const SwitchButton = (props: Props): JSX.Element => {
" "
)}
>
<span aria-hidden className={s.icon}>
<CheckIcon size={16} />
<span aria-hidden className={[s.icon, s.on].join(" ")}>
<DashIcon size={12} />
</span>
<span aria-hidden className={s.icon}>
<XIcon size={16} />
<span aria-hidden className={[s.icon].join(" ")}>
<DotIcon size={12} />
</span>
<span aria-hidden className={s.thumb} />
</Switch>
Expand Down
16 changes: 14 additions & 2 deletions src/web/toolbar/settings/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { shift, useFloating } from "@floating-ui/react-dom";
import { shift, size, useFloating } from "@floating-ui/react-dom";
import { Popover } from "@headlessui/react";
import { GearIcon } from "@primer/octicons-react";
import { Fragment } from "react";
Expand All @@ -11,7 +11,18 @@ import { ToolbarButton } from "./../button/button";
interface Props extends SettingsState, LayoutState {}

export const ToolbarSettings = (props: Props): JSX.Element => {
const float = useFloating({ middleware: [shift()] });
const sizeMdw = size({
apply: ({ elements, availableHeight, availableWidth }) => {
Object.assign(elements.floating.style, {
maxWidth: `${availableWidth}px`,
maxHeight: `${availableHeight}px`,
});
},
});

const float = useFloating({
middleware: [shift(), sizeMdw],
});

return (
<Popover>
Expand All @@ -26,6 +37,7 @@ export const ToolbarSettings = (props: Props): JSX.Element => {
position: float.strategy,
top: float.y ?? 0,
left: float.x ?? 0,
height: "100vh",
}}
>
<SettingsPanel {...props} />
Expand Down

0 comments on commit 92e7bab

Please sign in to comment.