Skip to content

Commit

Permalink
feat: new toolbar config 'placement' and 'items'
Browse files Browse the repository at this point in the history
  • Loading branch information
hyrious committed Jan 16, 2024
1 parent e183747 commit 9c0b48b
Show file tree
Hide file tree
Showing 19 changed files with 313 additions and 93 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

- Added toolbar config `placement: "left" | "right"` and `items: ToolbarItem[]` to further control the style of toolbar.

## 0.3.10

- Added method `jumpPage(index)`. Requires `@netless/window-manager` at least 0.4.63.
Expand Down
4 changes: 2 additions & 2 deletions packages/fastboard-react/test/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const search = new URLSearchParams(location.search);
const FastboardLayout: FastboardUIConfig = {
page_control: { enable: false },
redo_undo: { enable: true },
toolbar: { enable: true },
toolbar: { enable: true, placement: "right" },
zoom_control: { enable: true },
};

Expand All @@ -26,7 +26,7 @@ function App() {
uid: genUID(),
uuid: import.meta.env.VITE_ROOM_UUID,
roomToken: import.meta.env.VITE_ROOM_TOKEN,
isWritable: search.get("isWritable") === "1",
isWritable: search.get("isWritable") !== "0",
},
managerConfig: {
cursor: true,
Expand Down
11 changes: 11 additions & 0 deletions packages/fastboard-ui/src/components/Fastboard/Fastboard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@
}
}

.fastboard-right {
@extend .fastboard-left;
left: auto;
right: 0;

.fastboard-toolbar {
padding-left: 0;
padding-right: 16px;
}
}

.fastboard-bottom-left {
display: flex;
gap: 10px;
Expand Down
12 changes: 11 additions & 1 deletion packages/fastboard-ui/src/components/Fastboard/Fastboard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
layout = "visible";
}
$: toolbar_has_items =
!config.toolbar ||
!config.toolbar.items ||
!config.toolbar.apps ||
config.toolbar.items.length > 0 ||
config.toolbar.apps.enable !== false;
$: try {
if (app && container) {
app.bindContainer(container);
Expand Down Expand Up @@ -72,7 +79,10 @@

<div class="{name}-root" class:loading={!app}>
<div class="{name}-view" bind:this={container} on:touchstart|capture={focus_me} />
<div class="{name}-left" class:hidden={!(layout === "visible" || layout === "toolbar-only")}>
<div
class="{name}-{config.toolbar?.placement || 'left'}"
class:hidden={!toolbar_has_items || !(layout === "visible" || layout === "toolbar-only")}
>
{#if config.toolbar?.enable !== false}
<Toolbar {app} {theme} {language} config={config.toolbar} />
{/if}
Expand Down
10 changes: 10 additions & 0 deletions packages/fastboard-ui/src/components/Toolbar/Toolbar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,13 @@ $name: "fastboard-toolbar";

@import "./components/Slider.scss";
@import "./components/Contents.scss";

.fastboard-right .#{$name}.collapsed {
transform: translateX(100%);
}

.fastboard-right .#{$name}-handler {
left: auto;
right: 100%;
transform: rotate(180deg);
}
4 changes: 4 additions & 0 deletions packages/fastboard-ui/src/components/Toolbar/Toolbar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
$: computed_height = clamp($container_height, extra_height, $scroll_height + extra_height);
$: scrollable = $scroll_height + extra_height > $container_height;
$: placement = config.placement || "left";
$: items = config.items;
$: hide_apps = config.apps?.enable === false;
</script>

Expand All @@ -37,6 +39,8 @@
{scroll_height}
{computed_height}
{scrollable}
{placement}
{items}
{hide_apps}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,10 @@ $name: "fastboard-toolbar";
}
}
}

.fastboard-right .#{$name}-triangle {
right: auto;
left: 0;
border-left: 0;
border-right: 4px solid transparent;
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
<script lang="ts">
import type { Appliance, FastboardApp } from "@netless/fastboard-core";
import type { FastboardApp } from "@netless/fastboard-core";
import type { Writable } from "svelte/store";
import type { Placement } from "tippy.js";
import type { Language, Theme } from "../../../typings";
import type { Shape } from "./constants";
import { applianceShapes, shapesIcon, shapesIconActive } from "./constants";
import type { Language, Theme, ToolbarItem } from "../../../typings";
import { writable } from "svelte/store";
import { scrollHeight } from "../../../actions/height";
import { scrollTop } from "../../../actions/scroll";
import { tippy_hide_all } from "../../../actions/tippy";
import { clamp } from "../../helpers";
import { i18n } from "./constants";
import { apps } from "../../../behaviors";
import { tooltip } from "./helper";
import Icons from "../../Icons";
import Button from "../../Button";
import Button, { type ButtonProps } from "../../Button";
import StrokeWidth from "./StrokeWidth.svelte";
import StrokeColor from "./StrokeColor.svelte";
import TextColor from "./TextColor.svelte";
import Shapes from "./Shapes.svelte";
import { tippy_hide_all } from "../../../actions/tippy";
import SelectShapes from "./SelectShapes.svelte";
import Clicker from "../definitions/Clicker.svelte";
import Selector from "../definitions/Selector.svelte";
import Pencil from "../definitions/Pencil.svelte";
import Text from "../definitions/Text.svelte";
import Shapes from "../definitions/Shapes.svelte";
import Eraser from "../definitions/Eraser.svelte";
import Clear from "../definitions/Clear.svelte";
export let app: FastboardApp | null | undefined = null;
export let theme: Theme = "light";
Expand All @@ -27,19 +33,26 @@
export let scroll_height: Writable<number>;
export let computed_height = 0;
export let scrollable = false;
export let placement: "left" | "right" = "left";
export let items: ToolbarItem[] = ["clicker", "selector", "pencil", "text", "shapes", "eraser", "clear"];
export let hide_apps = false;
const name = "fastboard-toolbar";
let last_shape: Shape = "rectangle";
let pencil_panel: HTMLDivElement;
let text_panel: HTMLDivElement;
let shapes_panel: HTMLDivElement;
let apps_panel: HTMLDivElement;
let btn_props: { name: string; theme: Theme; disabled: boolean; placement: Placement };
$: btn_props = { name, theme, disabled, placement: "right" };
let btn_props: Partial<ButtonProps>;
$: btn_props = {
name,
theme,
disabled,
placement: placement === "left" ? "right" : "left",
menu_placement: placement === "left" ? "right-start" : "left-start",
};
$: t = i18n[language];
$: hotkeys = app?.hotKeys;
$: c = {
Expand All @@ -49,17 +62,11 @@
eraser: tooltip(t.eraser, hotkeys?.changeToEraser),
text: tooltip(t.text, hotkeys?.changeToText),
};
$: memberState = app?.memberState;
$: appliance = $memberState?.currentApplianceName;
$: shape = $memberState?.shapeType;
$: status = app?.appsStatus;
$: if (applianceShapes.includes(appliance as Appliance)) {
last_shape = appliance as Shape;
} else if (shape) {
last_shape = shape;
}
$: max_scroll = scrollable ? $scroll_height + (32 + 8) * 2 - computed_height : 0;
let top = writable(0);
Expand All @@ -83,13 +90,6 @@
function text() {
app?.setAppliance("text");
}
function select_last_shape() {
if (applianceShapes.includes(last_shape as Appliance)) {
app?.setAppliance(last_shape as Appliance);
} else {
app?.setAppliance("shape", last_shape as Exclude<Shape, Appliance>);
}
}
function eraser() {
app?.setAppliance("eraser");
}
Expand All @@ -104,53 +104,31 @@
</Button>
{/if}
<div class="{name}-scrollable" class:scrollable use:scrollHeight={scroll_height} use:scrollTop={top}>
<Button class="clicker" {...btn_props} on:click={clicker} content={c.clicker}>
{#if appliance === "clicker"}
<Icons.ClickFilled {theme} active />
{:else}
<Icons.Click {theme} />
{#each items as item}
{#if item === "clicker"}
<Clicker {appliance} {theme} {btn_props} on:click={clicker} content={c.clicker} />
{:else if item === "selector"}
<Selector {appliance} {theme} {btn_props} on:click={selector} content={c.selector} />
{:else if item === "pencil"}
<Pencil {appliance} {theme} {btn_props} on:click={pencil} content={c.pencil} menu={pencil_panel} />
{:else if item === "text"}
<Text {appliance} {theme} {btn_props} on:click={text} content={c.text} menu={text_panel} />
{:else if item === "shapes"}
<Shapes {app} {appliance} {theme} {btn_props} content={t.shapes} menu={shapes_panel} />
{:else if item === "eraser"}
<Eraser {appliance} {theme} {btn_props} on:click={eraser} content={c.eraser} />
{:else if item === "clear"}
<Clear {theme} {btn_props} on:click={clear} content={t.clear} />
{/if}
</Button>
<Button class="selector" {...btn_props} on:click={selector} content={c.selector}>
{#if appliance === "selector"}
<Icons.SelectorFilled {theme} active />
{:else}
<Icons.Selector {theme} />
{/if}
</Button>
<Button class="pencil" {...btn_props} on:click={pencil} content={c.pencil} menu={pencil_panel}>
{#if appliance === "pencil"}
<Icons.PencilFilled {theme} active />
{:else}
<Icons.Pencil {theme} />
{/if}
</Button>
<Button class="text" {...btn_props} on:click={text} content={c.text} menu={text_panel}>
{#if appliance === "text"}
<Icons.TextFilled {theme} active />
{:else}
<Icons.Text {theme} />
{/if}
</Button>
<Button class="shapes" {...btn_props} on:click={select_last_shape} content={t.shapes} menu={shapes_panel}>
{#if appliance === last_shape || (appliance === "shape" && shape === last_shape)}
<svelte:component this={shapesIconActive[last_shape]} {theme} active />
{:else}
<svelte:component this={shapesIcon[last_shape]} {theme} />
{/if}
</Button>
<Button class="eraser" {...btn_props} on:click={eraser} content={c.eraser}>
{#if appliance === "eraser"}
<Icons.EraserFilled {theme} active />
{:else}
<Icons.Eraser {theme} />
{/if}
</Button>
<Button class="clear" {...btn_props} on:click={clear} content={t.clear}>
<Icons.Clear {theme} />
</Button>
{/each}
{#if !hide_apps}
<Button class="apps" {...btn_props} content={t.apps} menu={apps_panel} menu_placement="right-end">
<Button
class="apps"
{...btn_props}
content={t.apps}
menu={apps_panel}
menu_placement={placement === "left" ? "right-end" : "left-end"}
>
<Icons.Apps {theme} />
</Button>
{/if}
Expand All @@ -171,7 +149,7 @@
<TextColor {app} {theme} {disabled} />
</div>
<div class="{name}-panel shapes" bind:this={shapes_panel}>
<Shapes {app} {theme} {language} {disabled} />
<SelectShapes {app} {theme} {language} {disabled} />
<div class="{name}-panel-divider" />
<StrokeWidth {app} {theme} {disabled} />
<div class="{name}-panel-divider" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script lang="ts">
import type { Theme } from "../../../typings";
import Button, { type ButtonProps } from "../../Button";
import Icons from "../../Icons";
export let btn_props: Partial<ButtonProps> = {};
export let content: ButtonProps["content"] | undefined;
export let theme: Theme = "light";
</script>

<Button class="clear" {...btn_props} on:click {content}>
<Icons.Clear {theme} />
</Button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import type { ApplianceNames } from "@netless/fastboard-core";
import type { Theme } from "../../../typings";
import Button, { type ButtonProps } from "../../Button";
import Icons from "../../Icons";
export let btn_props: Partial<ButtonProps> = {};
export let content: ButtonProps["content"] | undefined;
export let appliance: ApplianceNames | undefined;
export let theme: Theme = "light";
</script>

<Button class="clicker" {...btn_props} on:click {content}>
{#if appliance === "clicker"}
<Icons.ClickFilled {theme} active />
{:else}
<Icons.Click {theme} />
{/if}
</Button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import type { ApplianceNames } from "@netless/fastboard-core";
import type { Theme } from "../../../typings";
import Button, { type ButtonProps } from "../../Button";
import Icons from "../../Icons";
export let btn_props: Partial<ButtonProps> = {};
export let content: ButtonProps["content"] | undefined;
export let appliance: ApplianceNames | undefined;
export let theme: Theme = "light";
</script>

<Button class="eraser" {...btn_props} on:click {content}>
{#if appliance === "eraser"}
<Icons.EraserFilled {theme} active />
{:else}
<Icons.Eraser {theme} />
{/if}
</Button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
import type { ApplianceNames } from "@netless/fastboard-core";
import type { Theme } from "../../../typings";
import Button, { type ButtonProps } from "../../Button";
import Icons from "../../Icons";
export let btn_props: Partial<ButtonProps> = {};
export let content: ButtonProps["content"] | undefined;
export let menu: ButtonProps["menu"] | undefined;
export let appliance: ApplianceNames | undefined;
export let theme: Theme = "light";
</script>

<Button class="pencil" {...btn_props} on:click {content} {menu}>
{#if appliance === "pencil"}
<Icons.PencilFilled {theme} active />
{:else}
<Icons.Pencil {theme} />
{/if}
</Button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import type { ApplianceNames } from "@netless/fastboard-core";
import type { Theme } from "../../../typings";
import Button, { type ButtonProps } from "../../Button";
import Icons from "../../Icons";
export let btn_props: Partial<ButtonProps> = {};
export let content: ButtonProps["content"] | undefined;
export let appliance: ApplianceNames | undefined;
export let theme: Theme = "light";
</script>

<Button class="selector" {...btn_props} on:click {content}>
{#if appliance === "selector"}
<Icons.SelectorFilled {theme} active />
{:else}
<Icons.Selector {theme} />
{/if}
</Button>
Loading

0 comments on commit 9c0b48b

Please sign in to comment.