@netless/fastboard-ui 0.3.9 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -1
- package/dist/index.js +5089 -2983
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5089 -2983
- package/dist/index.mjs.map +1 -1
- package/dist/index.svelte.mjs +4670 -2590
- package/dist/index.svelte.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/Fastboard/Fastboard.scss +11 -0
- package/src/components/Fastboard/Fastboard.svelte +11 -1
- package/src/components/Icons/Drag.svelte +16 -0
- package/src/components/Icons/DragFilled.svelte +14 -0
- package/src/components/Icons/Laser.svelte +21 -0
- package/src/components/Icons/LaserFilled.svelte +14 -0
- package/src/components/Icons/index.ts +8 -0
- package/src/components/Toolbar/Toolbar.scss +10 -0
- package/src/components/Toolbar/Toolbar.svelte +4 -0
- package/src/components/Toolbar/components/Contents.scss +7 -0
- package/src/components/Toolbar/components/Contents.svelte +64 -72
- package/src/components/Toolbar/components/constants.ts +6 -4
- package/src/components/Toolbar/definitions/Clear.svelte +13 -0
- package/src/components/Toolbar/definitions/Clicker.svelte +19 -0
- package/src/components/Toolbar/definitions/Eraser.svelte +19 -0
- package/src/components/Toolbar/definitions/Hand.svelte +19 -0
- package/src/components/Toolbar/definitions/Laser.svelte +19 -0
- package/src/components/Toolbar/definitions/Pencil.svelte +20 -0
- package/src/components/Toolbar/definitions/Selector.svelte +19 -0
- package/src/components/Toolbar/definitions/Shapes.svelte +41 -0
- package/src/components/Toolbar/definitions/Text.svelte +20 -0
- package/src/typings.ts +21 -18
- /package/src/components/Toolbar/components/{Shapes.svelte → SelectShapes.svelte} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netless/fastboard-ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "The front-end of @netless/fastboard-core.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"svelte": "dist/index.svelte.mjs",
|
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
],
|
|
11
11
|
"repository": "netless-io/fastboard",
|
|
12
12
|
"peerDependencies": {
|
|
13
|
-
"@netless/fastboard-core": "0.3.
|
|
13
|
+
"@netless/fastboard-core": "0.3.11"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"tippy.js": "^6.3.7"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@netless/
|
|
19
|
+
"@netless/buildtool": "0.1.0",
|
|
20
20
|
"@netless/esbuild-plugin-inline-sass": "0.1.0",
|
|
21
|
-
"@netless/
|
|
21
|
+
"@netless/fastboard-core": "0.3.11"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"cleanup": "rimraf dist",
|
|
@@ -39,6 +39,13 @@
|
|
|
39
39
|
layout = "visible";
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
$: toolbar_has_items =
|
|
43
|
+
!config.toolbar ||
|
|
44
|
+
!config.toolbar.items ||
|
|
45
|
+
!config.toolbar.apps ||
|
|
46
|
+
config.toolbar.items.length > 0 ||
|
|
47
|
+
config.toolbar.apps.enable !== false;
|
|
48
|
+
|
|
42
49
|
$: try {
|
|
43
50
|
if (app && container) {
|
|
44
51
|
app.bindContainer(container);
|
|
@@ -72,7 +79,10 @@
|
|
|
72
79
|
|
|
73
80
|
<div class="{name}-root" class:loading={!app}>
|
|
74
81
|
<div class="{name}-view" bind:this={container} on:touchstart|capture={focus_me} />
|
|
75
|
-
<div
|
|
82
|
+
<div
|
|
83
|
+
class="{name}-{config.toolbar?.placement || 'left'}"
|
|
84
|
+
class:hidden={!toolbar_has_items || !(layout === "visible" || layout === "toolbar-only")}
|
|
85
|
+
>
|
|
76
86
|
{#if config.toolbar?.enable !== false}
|
|
77
87
|
<Toolbar {app} {theme} {language} config={config.toolbar} />
|
|
78
88
|
{/if}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Theme } from "../../typings";
|
|
3
|
+
|
|
4
|
+
export let theme: Theme = "light";
|
|
5
|
+
export let active = false;
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<svg fill="none" viewBox="0 0 24 24" class="fastboard-icon {theme}" class:is-active={active}>
|
|
9
|
+
<path
|
|
10
|
+
d="M17.143 8.143v2.571h-3.857V6.857h2.571L12 3 8.143 6.857h2.571v3.857H6.857V8.143L3 12l1.286 1.286 2.571 2.571v-2.571h3.857v3.857H8.143L12 21l1.286-1.286 2.571-2.571h-2.571v-3.857h3.857v2.571L21 12l-3.857-3.857Z"
|
|
11
|
+
stroke="#5D6066"
|
|
12
|
+
stroke-width="1.25"
|
|
13
|
+
stroke-linejoin="round"
|
|
14
|
+
class="fastboard-icon-stroke-color"
|
|
15
|
+
/>
|
|
16
|
+
</svg>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Theme } from "../../typings";
|
|
3
|
+
|
|
4
|
+
export let theme: Theme = "light";
|
|
5
|
+
export let active = false;
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<svg fill="none" viewBox="0 0 24 24" class="fastboard-icon {theme}" class:is-active={active}>
|
|
9
|
+
<path
|
|
10
|
+
d="M17.143 8.143v2.571h-3.857V6.857h2.571L12 3 8.143 6.857h2.571v3.857H6.857V8.143L3 12l1.286 1.286 2.571 2.571v-2.571h3.857v3.857H8.143L12 21l1.286-1.286 2.571-2.571h-2.571v-3.857h3.857v2.571L21 12l-3.857-3.857Z"
|
|
11
|
+
fill="#5D6066"
|
|
12
|
+
class="fastboard-icon-fill-color"
|
|
13
|
+
/>
|
|
14
|
+
</svg>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Theme } from "../../typings";
|
|
3
|
+
|
|
4
|
+
export let theme: Theme = "light";
|
|
5
|
+
export let active = false;
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<svg fill="none" viewBox="0 0 24 24" class="fastboard-icon {theme}" class:is-active={active}>
|
|
9
|
+
<path
|
|
10
|
+
d="m11.48 10.033 2.695 2.696m-2.695-2.696-7.375 7.379a.364.364 0 0 0 0 .515l2.18 2.182a.361.361 0 0 0 .514 0l7.376-7.38m-2.695-2.696 2.438-2.438a.363.363 0 0 1 .514 0l2.18 2.182v-.001a.363.363 0 0 1 0 .514l-2.437 2.439"
|
|
11
|
+
stroke="#5D6066"
|
|
12
|
+
stroke-width="1.25"
|
|
13
|
+
stroke-linejoin="round"
|
|
14
|
+
class="fastboard-icon-stroke-color"
|
|
15
|
+
/>
|
|
16
|
+
<path
|
|
17
|
+
d="M10.895 6.652a.363.363 0 0 0-.13-.182c-.348-.399-.338-1.264.032-1.634a.362.362 0 1 0-.513-.514c-.18.18-.491.286-.834.286-.343 0-.654-.107-.833-.286a.363.363 0 1 0-.514.514c.38.382.38 1.286 0 1.667a.364.364 0 0 0 .514.515c.179-.18.49-.287.833-.287.343 0 .654.107.834.287a.362.362 0 0 0 .256.106h.008a.363.363 0 0 0 .347-.472Zm6.294-.149a.366.366 0 0 0 .118.594.363.363 0 0 0 .396-.079c.18-.18.49-.287.834-.287.343 0 .654.107.832.287a.362.362 0 0 0 .258.106h.007a.363.363 0 0 0 .218-.654c-.35-.399-.338-1.264.032-1.634a.363.363 0 1 0-.515-.514c-.178.18-.49.286-.832.286-.343 0-.654-.107-.834-.286a.364.364 0 0 0-.514.514c.382.382.382 1.286 0 1.667Zm2.794 9.239a.363.363 0 0 0-.13-.182c-.35-.398-.34-1.263.03-1.633a.363.363 0 1 0-.514-.515c-.178.18-.49.287-.832.287-.343 0-.654-.107-.834-.287a.365.365 0 0 0-.514.515c.382.38.382 1.285 0 1.667a.364.364 0 0 0 .514.514c.18-.18.49-.286.834-.286.343 0 .654.107.832.286a.363.363 0 0 0 .258.107h.007a.363.363 0 0 0 .349-.473Z"
|
|
18
|
+
fill="#5D6066"
|
|
19
|
+
class="fastboard-icon-fill-color"
|
|
20
|
+
/>
|
|
21
|
+
</svg>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Theme } from "../../typings";
|
|
3
|
+
|
|
4
|
+
export let theme: Theme = "light";
|
|
5
|
+
export let active = false;
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<svg fill="none" viewBox="0 0 24 24" class="fastboard-icon {theme}" class:is-active={active}>
|
|
9
|
+
<path
|
|
10
|
+
d="m11.48 10.033 2.695 2.696-7.376 7.38a.361.361 0 0 1-.514 0l-2.18-2.182a.362.362 0 0 1 0-.515l7.375-7.379Zm5.133-.257a.363.363 0 0 1 0 .514l-1.925 1.925-2.694-2.696 1.924-1.924a.363.363 0 0 1 .514 0l2.18 2.182v-.001Zm-5.718-3.124a.363.363 0 0 0-.13-.182c-.348-.399-.338-1.264.032-1.634a.362.362 0 1 0-.513-.514c-.18.18-.491.286-.834.286-.343 0-.654-.107-.833-.286a.363.363 0 1 0-.514.514c.38.382.38 1.286 0 1.667a.364.364 0 0 0 .514.515c.179-.18.49-.287.833-.287.343 0 .654.107.834.287a.362.362 0 0 0 .256.106h.008a.363.363 0 0 0 .347-.472Zm6.294-.149a.366.366 0 0 0 .118.594.363.363 0 0 0 .396-.079c.18-.18.49-.287.834-.287.343 0 .654.107.832.287a.362.362 0 0 0 .258.106h.007a.363.363 0 0 0 .218-.654c-.35-.399-.338-1.264.032-1.634a.363.363 0 1 0-.515-.514c-.178.18-.49.286-.832.286-.343 0-.654-.107-.834-.286a.364.364 0 0 0-.514.514c.382.382.382 1.286 0 1.667Zm2.794 9.239a.363.363 0 0 0-.13-.182c-.35-.398-.34-1.263.03-1.633a.363.363 0 1 0-.514-.515c-.178.18-.49.287-.832.287-.343 0-.654-.107-.834-.287a.365.365 0 0 0-.514.515c.382.38.382 1.285 0 1.667a.364.364 0 0 0 .514.514c.18-.18.49-.286.834-.286.343 0 .654.107.832.286a.363.363 0 0 0 .258.107h.007a.363.363 0 0 0 .349-.473Z"
|
|
11
|
+
fill="#5D6066"
|
|
12
|
+
class="fastboard-icon-fill-color"
|
|
13
|
+
/>
|
|
14
|
+
</svg>
|
|
@@ -10,8 +10,12 @@ import Click from "./Click.svelte";
|
|
|
10
10
|
import ClickFilled from "./ClickFilled.svelte";
|
|
11
11
|
import Diamond from "./Diamond.svelte";
|
|
12
12
|
import Down from "./Down.svelte";
|
|
13
|
+
import Drag from "./Drag.svelte";
|
|
14
|
+
import DragFilled from "./DragFilled.svelte";
|
|
13
15
|
import Eraser from "./Eraser.svelte";
|
|
14
16
|
import EraserFilled from "./EraserFilled.svelte";
|
|
17
|
+
import Laser from "./Laser.svelte";
|
|
18
|
+
import LaserFilled from "./LaserFilled.svelte";
|
|
15
19
|
import Left from "./Left.svelte";
|
|
16
20
|
import Line from "./Line.svelte";
|
|
17
21
|
import LineBolded from "./LineBolded.svelte";
|
|
@@ -55,8 +59,12 @@ const Icons = {
|
|
|
55
59
|
ClickFilled,
|
|
56
60
|
Diamond,
|
|
57
61
|
Down,
|
|
62
|
+
Drag,
|
|
63
|
+
DragFilled,
|
|
58
64
|
Eraser,
|
|
59
65
|
EraserFilled,
|
|
66
|
+
Laser,
|
|
67
|
+
LaserFilled,
|
|
60
68
|
Left,
|
|
61
69
|
Line,
|
|
62
70
|
LineBolded,
|
|
@@ -76,3 +76,13 @@ $name: "fastboard-toolbar";
|
|
|
76
76
|
|
|
77
77
|
@import "./components/Slider.scss";
|
|
78
78
|
@import "./components/Contents.scss";
|
|
79
|
+
|
|
80
|
+
.fastboard-right .#{$name}.collapsed {
|
|
81
|
+
transform: translateX(100%);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.fastboard-right .#{$name}-handler {
|
|
85
|
+
left: auto;
|
|
86
|
+
right: 100%;
|
|
87
|
+
transform: rotate(180deg);
|
|
88
|
+
}
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
$: computed_height = clamp($container_height, extra_height, $scroll_height + extra_height);
|
|
25
25
|
$: scrollable = $scroll_height + extra_height > $container_height;
|
|
26
26
|
|
|
27
|
+
$: placement = config.placement || "left";
|
|
28
|
+
$: items = config.items;
|
|
27
29
|
$: hide_apps = config.apps?.enable === false;
|
|
28
30
|
</script>
|
|
29
31
|
|
|
@@ -37,6 +39,8 @@
|
|
|
37
39
|
{scroll_height}
|
|
38
40
|
{computed_height}
|
|
39
41
|
{scrollable}
|
|
42
|
+
{placement}
|
|
43
|
+
{items}
|
|
40
44
|
{hide_apps}
|
|
41
45
|
/>
|
|
42
46
|
</div>
|
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type {
|
|
2
|
+
import type { FastboardApp } from "@netless/fastboard-core";
|
|
3
3
|
import type { Writable } from "svelte/store";
|
|
4
|
-
import type {
|
|
5
|
-
import type { Language, Theme } from "../../../typings";
|
|
6
|
-
import type { Shape } from "./constants";
|
|
7
|
-
import { applianceShapes, shapesIcon, shapesIconActive } from "./constants";
|
|
4
|
+
import type { Language, Theme, ToolbarItem } from "../../../typings";
|
|
8
5
|
import { writable } from "svelte/store";
|
|
9
6
|
import { scrollHeight } from "../../../actions/height";
|
|
10
7
|
import { scrollTop } from "../../../actions/scroll";
|
|
8
|
+
import { tippy_hide_all } from "../../../actions/tippy";
|
|
11
9
|
import { clamp } from "../../helpers";
|
|
12
10
|
import { i18n } from "./constants";
|
|
13
11
|
import { apps } from "../../../behaviors";
|
|
14
12
|
import { tooltip } from "./helper";
|
|
15
13
|
import Icons from "../../Icons";
|
|
16
|
-
import Button from "../../Button";
|
|
14
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
15
|
+
|
|
17
16
|
import StrokeWidth from "./StrokeWidth.svelte";
|
|
18
17
|
import StrokeColor from "./StrokeColor.svelte";
|
|
19
18
|
import TextColor from "./TextColor.svelte";
|
|
20
|
-
import
|
|
21
|
-
|
|
19
|
+
import SelectShapes from "./SelectShapes.svelte";
|
|
20
|
+
|
|
21
|
+
import Clicker from "../definitions/Clicker.svelte";
|
|
22
|
+
import Selector from "../definitions/Selector.svelte";
|
|
23
|
+
import Pencil from "../definitions/Pencil.svelte";
|
|
24
|
+
import Text from "../definitions/Text.svelte";
|
|
25
|
+
import Shapes from "../definitions/Shapes.svelte";
|
|
26
|
+
import Eraser from "../definitions/Eraser.svelte";
|
|
27
|
+
import Clear from "../definitions/Clear.svelte";
|
|
28
|
+
import Hand from "../definitions/Hand.svelte";
|
|
29
|
+
import Laser from "../definitions/Laser.svelte";
|
|
22
30
|
|
|
23
31
|
export let app: FastboardApp | null | undefined = null;
|
|
24
32
|
export let theme: Theme = "light";
|
|
@@ -27,19 +35,26 @@
|
|
|
27
35
|
export let scroll_height: Writable<number>;
|
|
28
36
|
export let computed_height = 0;
|
|
29
37
|
export let scrollable = false;
|
|
38
|
+
export let placement: "left" | "right" = "left";
|
|
39
|
+
export let items: ToolbarItem[] = ["clicker", "selector", "pencil", "text", "shapes", "eraser", "clear"];
|
|
30
40
|
export let hide_apps = false;
|
|
31
41
|
|
|
32
42
|
const name = "fastboard-toolbar";
|
|
33
43
|
|
|
34
|
-
let last_shape: Shape = "rectangle";
|
|
35
|
-
|
|
36
44
|
let pencil_panel: HTMLDivElement;
|
|
37
45
|
let text_panel: HTMLDivElement;
|
|
38
46
|
let shapes_panel: HTMLDivElement;
|
|
39
47
|
let apps_panel: HTMLDivElement;
|
|
40
48
|
|
|
41
|
-
let btn_props:
|
|
42
|
-
$: btn_props = {
|
|
49
|
+
let btn_props: Partial<ButtonProps>;
|
|
50
|
+
$: btn_props = {
|
|
51
|
+
name,
|
|
52
|
+
theme,
|
|
53
|
+
disabled,
|
|
54
|
+
placement: placement === "left" ? "right" : "left",
|
|
55
|
+
menu_placement: placement === "left" ? "right-start" : "left-start",
|
|
56
|
+
};
|
|
57
|
+
|
|
43
58
|
$: t = i18n[language];
|
|
44
59
|
$: hotkeys = app?.hotKeys;
|
|
45
60
|
$: c = {
|
|
@@ -48,18 +63,14 @@
|
|
|
48
63
|
pencil: tooltip(t.pencil, hotkeys?.changeToPencil),
|
|
49
64
|
eraser: tooltip(t.eraser, hotkeys?.changeToEraser),
|
|
50
65
|
text: tooltip(t.text, hotkeys?.changeToText),
|
|
66
|
+
hand: tooltip(t.hand, hotkeys?.changeToHand),
|
|
67
|
+
laserPointer: tooltip(t.laserPointer, hotkeys?.changeToLaserPointer),
|
|
51
68
|
};
|
|
69
|
+
|
|
52
70
|
$: memberState = app?.memberState;
|
|
53
71
|
$: appliance = $memberState?.currentApplianceName;
|
|
54
|
-
$: shape = $memberState?.shapeType;
|
|
55
72
|
$: status = app?.appsStatus;
|
|
56
73
|
|
|
57
|
-
$: if (applianceShapes.includes(appliance as Appliance)) {
|
|
58
|
-
last_shape = appliance as Shape;
|
|
59
|
-
} else if (shape) {
|
|
60
|
-
last_shape = shape;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
74
|
$: max_scroll = scrollable ? $scroll_height + (32 + 8) * 2 - computed_height : 0;
|
|
64
75
|
|
|
65
76
|
let top = writable(0);
|
|
@@ -83,16 +94,15 @@
|
|
|
83
94
|
function text() {
|
|
84
95
|
app?.setAppliance("text");
|
|
85
96
|
}
|
|
86
|
-
function select_last_shape() {
|
|
87
|
-
if (applianceShapes.includes(last_shape as Appliance)) {
|
|
88
|
-
app?.setAppliance(last_shape as Appliance);
|
|
89
|
-
} else {
|
|
90
|
-
app?.setAppliance("shape", last_shape as Exclude<Shape, Appliance>);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
97
|
function eraser() {
|
|
94
98
|
app?.setAppliance("eraser");
|
|
95
99
|
}
|
|
100
|
+
function hand() {
|
|
101
|
+
app?.setAppliance("hand");
|
|
102
|
+
}
|
|
103
|
+
function laserPointer() {
|
|
104
|
+
app?.setAppliance("laserPointer");
|
|
105
|
+
}
|
|
96
106
|
function clear() {
|
|
97
107
|
app?.cleanCurrentScene();
|
|
98
108
|
}
|
|
@@ -104,53 +114,35 @@
|
|
|
104
114
|
</Button>
|
|
105
115
|
{/if}
|
|
106
116
|
<div class="{name}-scrollable" class:scrollable use:scrollHeight={scroll_height} use:scrollTop={top}>
|
|
107
|
-
|
|
108
|
-
{#if
|
|
109
|
-
<
|
|
110
|
-
{:else}
|
|
111
|
-
<
|
|
117
|
+
{#each items as item}
|
|
118
|
+
{#if item === "clicker"}
|
|
119
|
+
<Clicker {appliance} {theme} {btn_props} on:click={clicker} content={c.clicker} />
|
|
120
|
+
{:else if item === "selector"}
|
|
121
|
+
<Selector {appliance} {theme} {btn_props} on:click={selector} content={c.selector} />
|
|
122
|
+
{:else if item === "pencil"}
|
|
123
|
+
<Pencil {appliance} {theme} {btn_props} on:click={pencil} content={c.pencil} menu={pencil_panel} />
|
|
124
|
+
{:else if item === "text"}
|
|
125
|
+
<Text {appliance} {theme} {btn_props} on:click={text} content={c.text} menu={text_panel} />
|
|
126
|
+
{:else if item === "shapes"}
|
|
127
|
+
<Shapes {app} {appliance} {theme} {btn_props} content={t.shapes} menu={shapes_panel} />
|
|
128
|
+
{:else if item === "eraser"}
|
|
129
|
+
<Eraser {appliance} {theme} {btn_props} on:click={eraser} content={c.eraser} />
|
|
130
|
+
{:else if item === "clear"}
|
|
131
|
+
<Clear {theme} {btn_props} on:click={clear} content={t.clear} />
|
|
132
|
+
{:else if item === "hand"}
|
|
133
|
+
<Hand {appliance} {theme} {btn_props} on:click={hand} content={c.hand} />
|
|
134
|
+
{:else if item === "laserPointer"}
|
|
135
|
+
<Laser {appliance} {theme} {btn_props} on:click={laserPointer} content={c.laserPointer} />
|
|
112
136
|
{/if}
|
|
113
|
-
|
|
114
|
-
<Button class="selector" {...btn_props} on:click={selector} content={c.selector}>
|
|
115
|
-
{#if appliance === "selector"}
|
|
116
|
-
<Icons.SelectorFilled {theme} active />
|
|
117
|
-
{:else}
|
|
118
|
-
<Icons.Selector {theme} />
|
|
119
|
-
{/if}
|
|
120
|
-
</Button>
|
|
121
|
-
<Button class="pencil" {...btn_props} on:click={pencil} content={c.pencil} menu={pencil_panel}>
|
|
122
|
-
{#if appliance === "pencil"}
|
|
123
|
-
<Icons.PencilFilled {theme} active />
|
|
124
|
-
{:else}
|
|
125
|
-
<Icons.Pencil {theme} />
|
|
126
|
-
{/if}
|
|
127
|
-
</Button>
|
|
128
|
-
<Button class="text" {...btn_props} on:click={text} content={c.text} menu={text_panel}>
|
|
129
|
-
{#if appliance === "text"}
|
|
130
|
-
<Icons.TextFilled {theme} active />
|
|
131
|
-
{:else}
|
|
132
|
-
<Icons.Text {theme} />
|
|
133
|
-
{/if}
|
|
134
|
-
</Button>
|
|
135
|
-
<Button class="shapes" {...btn_props} on:click={select_last_shape} content={t.shapes} menu={shapes_panel}>
|
|
136
|
-
{#if appliance === last_shape || (appliance === "shape" && shape === last_shape)}
|
|
137
|
-
<svelte:component this={shapesIconActive[last_shape]} {theme} active />
|
|
138
|
-
{:else}
|
|
139
|
-
<svelte:component this={shapesIcon[last_shape]} {theme} />
|
|
140
|
-
{/if}
|
|
141
|
-
</Button>
|
|
142
|
-
<Button class="eraser" {...btn_props} on:click={eraser} content={c.eraser}>
|
|
143
|
-
{#if appliance === "eraser"}
|
|
144
|
-
<Icons.EraserFilled {theme} active />
|
|
145
|
-
{:else}
|
|
146
|
-
<Icons.Eraser {theme} />
|
|
147
|
-
{/if}
|
|
148
|
-
</Button>
|
|
149
|
-
<Button class="clear" {...btn_props} on:click={clear} content={t.clear}>
|
|
150
|
-
<Icons.Clear {theme} />
|
|
151
|
-
</Button>
|
|
137
|
+
{/each}
|
|
152
138
|
{#if !hide_apps}
|
|
153
|
-
<Button
|
|
139
|
+
<Button
|
|
140
|
+
class="apps"
|
|
141
|
+
{...btn_props}
|
|
142
|
+
content={t.apps}
|
|
143
|
+
menu={apps_panel}
|
|
144
|
+
menu_placement={placement === "left" ? "right-end" : "left-end"}
|
|
145
|
+
>
|
|
154
146
|
<Icons.Apps {theme} />
|
|
155
147
|
</Button>
|
|
156
148
|
{/if}
|
|
@@ -171,7 +163,7 @@
|
|
|
171
163
|
<TextColor {app} {theme} {disabled} />
|
|
172
164
|
</div>
|
|
173
165
|
<div class="{name}-panel shapes" bind:this={shapes_panel}>
|
|
174
|
-
<
|
|
166
|
+
<SelectShapes {app} {theme} {language} {disabled} />
|
|
175
167
|
<div class="{name}-panel-divider" />
|
|
176
168
|
<StrokeWidth {app} {theme} {disabled} />
|
|
177
169
|
<div class="{name}-panel-divider" />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Appliance, Color } from "@netless/fastboard-core";
|
|
2
|
-
import type { I18nData } from "../../../typings";
|
|
2
|
+
import type { I18nData, ToolbarItem } from "../../../typings";
|
|
3
3
|
import Icons from "../../Icons";
|
|
4
4
|
|
|
5
5
|
export const colors: Record<string, Color> = {
|
|
@@ -52,9 +52,7 @@ export const shapesIconActive: Record<Shape, any> = {
|
|
|
52
52
|
speechBalloon: Icons.BalloonBolded,
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
export const i18n: I18nData<
|
|
56
|
-
"clicker" | "selector" | "pencil" | "text" | "shapes" | "eraser" | "clear" | "apps"
|
|
57
|
-
> = {
|
|
55
|
+
export const i18n: I18nData<ToolbarItem | "apps"> = {
|
|
58
56
|
en: {
|
|
59
57
|
clicker: "clicker",
|
|
60
58
|
selector: "selector",
|
|
@@ -64,6 +62,8 @@ export const i18n: I18nData<
|
|
|
64
62
|
shapes: "shapes",
|
|
65
63
|
clear: "clear",
|
|
66
64
|
apps: "apps",
|
|
65
|
+
hand: "hand",
|
|
66
|
+
laserPointer: "laser pointer",
|
|
67
67
|
},
|
|
68
68
|
"zh-CN": {
|
|
69
69
|
clicker: "点击",
|
|
@@ -74,6 +74,8 @@ export const i18n: I18nData<
|
|
|
74
74
|
shapes: "形状",
|
|
75
75
|
clear: "清屏",
|
|
76
76
|
apps: "Apps",
|
|
77
|
+
hand: "抓手",
|
|
78
|
+
laserPointer: "激光笔",
|
|
77
79
|
},
|
|
78
80
|
};
|
|
79
81
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Theme } from "../../../typings";
|
|
3
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
4
|
+
import Icons from "../../Icons";
|
|
5
|
+
|
|
6
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
7
|
+
export let content: ButtonProps["content"] | undefined;
|
|
8
|
+
export let theme: Theme = "light";
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<Button class="clear" {...btn_props} on:click {content}>
|
|
12
|
+
<Icons.Clear {theme} />
|
|
13
|
+
</Button>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ApplianceNames } from "@netless/fastboard-core";
|
|
3
|
+
import type { Theme } from "../../../typings";
|
|
4
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
5
|
+
import Icons from "../../Icons";
|
|
6
|
+
|
|
7
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
8
|
+
export let content: ButtonProps["content"] | undefined;
|
|
9
|
+
export let appliance: ApplianceNames | undefined;
|
|
10
|
+
export let theme: Theme = "light";
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<Button class="clicker" {...btn_props} on:click {content}>
|
|
14
|
+
{#if appliance === "clicker"}
|
|
15
|
+
<Icons.ClickFilled {theme} active />
|
|
16
|
+
{:else}
|
|
17
|
+
<Icons.Click {theme} />
|
|
18
|
+
{/if}
|
|
19
|
+
</Button>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ApplianceNames } from "@netless/fastboard-core";
|
|
3
|
+
import type { Theme } from "../../../typings";
|
|
4
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
5
|
+
import Icons from "../../Icons";
|
|
6
|
+
|
|
7
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
8
|
+
export let content: ButtonProps["content"] | undefined;
|
|
9
|
+
export let appliance: ApplianceNames | undefined;
|
|
10
|
+
export let theme: Theme = "light";
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<Button class="eraser" {...btn_props} on:click {content}>
|
|
14
|
+
{#if appliance === "eraser"}
|
|
15
|
+
<Icons.EraserFilled {theme} active />
|
|
16
|
+
{:else}
|
|
17
|
+
<Icons.Eraser {theme} />
|
|
18
|
+
{/if}
|
|
19
|
+
</Button>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ApplianceNames } from "@netless/fastboard-core";
|
|
3
|
+
import type { Theme } from "../../../typings";
|
|
4
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
5
|
+
import Icons from "../../Icons";
|
|
6
|
+
|
|
7
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
8
|
+
export let content: ButtonProps["content"] | undefined;
|
|
9
|
+
export let appliance: ApplianceNames | undefined;
|
|
10
|
+
export let theme: Theme = "light";
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<Button class="hand" {...btn_props} on:click {content}>
|
|
14
|
+
{#if appliance === "hand"}
|
|
15
|
+
<Icons.DragFilled {theme} active />
|
|
16
|
+
{:else}
|
|
17
|
+
<Icons.Drag {theme} />
|
|
18
|
+
{/if}
|
|
19
|
+
</Button>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ApplianceNames } from "@netless/fastboard-core";
|
|
3
|
+
import type { Theme } from "../../../typings";
|
|
4
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
5
|
+
import Icons from "../../Icons";
|
|
6
|
+
|
|
7
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
8
|
+
export let content: ButtonProps["content"] | undefined;
|
|
9
|
+
export let appliance: ApplianceNames | undefined;
|
|
10
|
+
export let theme: Theme = "light";
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<Button class="laserPointer" {...btn_props} on:click {content}>
|
|
14
|
+
{#if appliance === "laserPointer"}
|
|
15
|
+
<Icons.LaserFilled {theme} active />
|
|
16
|
+
{:else}
|
|
17
|
+
<Icons.Laser {theme} />
|
|
18
|
+
{/if}
|
|
19
|
+
</Button>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ApplianceNames } from "@netless/fastboard-core";
|
|
3
|
+
import type { Theme } from "../../../typings";
|
|
4
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
5
|
+
import Icons from "../../Icons";
|
|
6
|
+
|
|
7
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
8
|
+
export let content: ButtonProps["content"] | undefined;
|
|
9
|
+
export let menu: ButtonProps["menu"] | undefined;
|
|
10
|
+
export let appliance: ApplianceNames | undefined;
|
|
11
|
+
export let theme: Theme = "light";
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Button class="pencil" {...btn_props} on:click {content} {menu}>
|
|
15
|
+
{#if appliance === "pencil"}
|
|
16
|
+
<Icons.PencilFilled {theme} active />
|
|
17
|
+
{:else}
|
|
18
|
+
<Icons.Pencil {theme} />
|
|
19
|
+
{/if}
|
|
20
|
+
</Button>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ApplianceNames } from "@netless/fastboard-core";
|
|
3
|
+
import type { Theme } from "../../../typings";
|
|
4
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
5
|
+
import Icons from "../../Icons";
|
|
6
|
+
|
|
7
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
8
|
+
export let content: ButtonProps["content"] | undefined;
|
|
9
|
+
export let appliance: ApplianceNames | undefined;
|
|
10
|
+
export let theme: Theme = "light";
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<Button class="selector" {...btn_props} on:click {content}>
|
|
14
|
+
{#if appliance === "selector"}
|
|
15
|
+
<Icons.SelectorFilled {theme} active />
|
|
16
|
+
{:else}
|
|
17
|
+
<Icons.Selector {theme} />
|
|
18
|
+
{/if}
|
|
19
|
+
</Button>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Appliance, ApplianceNames, FastboardApp } from "@netless/fastboard-core";
|
|
3
|
+
import type { Theme } from "../../../typings";
|
|
4
|
+
import { applianceShapes, shapesIcon, shapesIconActive, type Shape } from "../components/constants";
|
|
5
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
6
|
+
|
|
7
|
+
export let app: FastboardApp | null | undefined = null;
|
|
8
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
9
|
+
export let content: ButtonProps["content"] | undefined;
|
|
10
|
+
export let menu: ButtonProps["menu"] | undefined;
|
|
11
|
+
export let appliance: ApplianceNames | undefined;
|
|
12
|
+
export let theme: Theme = "light";
|
|
13
|
+
|
|
14
|
+
$: memberState = app?.memberState;
|
|
15
|
+
$: appliance = $memberState?.currentApplianceName;
|
|
16
|
+
$: shape = $memberState?.shapeType;
|
|
17
|
+
|
|
18
|
+
let last_shape: Shape = "rectangle";
|
|
19
|
+
|
|
20
|
+
$: if (applianceShapes.includes(appliance as Appliance)) {
|
|
21
|
+
last_shape = appliance as Shape;
|
|
22
|
+
} else if (shape) {
|
|
23
|
+
last_shape = shape;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function select_last_shape() {
|
|
27
|
+
if (applianceShapes.includes(last_shape as Appliance)) {
|
|
28
|
+
app?.setAppliance(last_shape as Appliance);
|
|
29
|
+
} else {
|
|
30
|
+
app?.setAppliance("shape", last_shape as Exclude<Shape, Appliance>);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<Button class="shapes" {...btn_props} on:click={select_last_shape} {content} {menu}>
|
|
36
|
+
{#if appliance === last_shape || (appliance === "shape" && shape === last_shape)}
|
|
37
|
+
<svelte:component this={shapesIconActive[last_shape]} {theme} active />
|
|
38
|
+
{:else}
|
|
39
|
+
<svelte:component this={shapesIcon[last_shape]} {theme} />
|
|
40
|
+
{/if}
|
|
41
|
+
</Button>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ApplianceNames } from "@netless/fastboard-core";
|
|
3
|
+
import type { Theme } from "../../../typings";
|
|
4
|
+
import Button, { type ButtonProps } from "../../Button";
|
|
5
|
+
import Icons from "../../Icons";
|
|
6
|
+
|
|
7
|
+
export let btn_props: Partial<ButtonProps> = {};
|
|
8
|
+
export let content: ButtonProps["content"] | undefined;
|
|
9
|
+
export let menu: ButtonProps["menu"] | undefined;
|
|
10
|
+
export let appliance: ApplianceNames | undefined;
|
|
11
|
+
export let theme: Theme = "light";
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Button class="text" {...btn_props} on:click {content} {menu}>
|
|
15
|
+
{#if appliance === "text"}
|
|
16
|
+
<Icons.TextFilled {theme} active />
|
|
17
|
+
{:else}
|
|
18
|
+
<Icons.Text {theme} />
|
|
19
|
+
{/if}
|
|
20
|
+
</Button>
|