Skip to content

Commit

Permalink
Merge pull request #628 from tuanchauict/app-ui-state
Browse files Browse the repository at this point in the history
Link data and shape tool part 1
  • Loading branch information
tuanchauict authored Dec 16, 2024
2 parents 59dc48a + 9d5fd38 commit b85b7e8
Show file tree
Hide file tree
Showing 22 changed files with 814 additions and 190 deletions.
13 changes: 7 additions & 6 deletions monosketch-svelte/src/app/app-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,24 @@ export class AppContext {

shapeManager = new ShapeManager();

actionManager = new ActionManager(this.appLifecycleOwner);

onStart = (): void => {
this.appLifecycleOwner.onStart();

this.init();

this.appUiStateManager.observeTheme();
this.actionManager.observeKeyCommand(
this.appUiStateManager.keyCommandFlow.map((keyCommand) => keyCommand.command),
);
};

private init() {
const actionManager = new ActionManager(
this.appLifecycleOwner,
this.appUiStateManager.keyCommandFlow.map((keyCommand) => keyCommand.command),
);
actionManager.installDebugCommand();
this.actionManager.installDebugCommand();

const browserManager = new BrowserManager((projectId: string) => {
actionManager.setOneTimeAction(OneTimeAction.ProjectAction.SwitchProject(projectId));
this.actionManager.setOneTimeAction(OneTimeAction.ProjectAction.SwitchProject(projectId));
});
browserManager.startObserveStateChange(
this.shapeManager.rootIdFlow,
Expand Down
11 changes: 11 additions & 0 deletions monosketch-svelte/src/lib/libs/sequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ export function getOrDefault<T>(array: T[], index: number, defaultValue: T): T {
return index >= 0 && index < array.length ? array[index] : defaultValue;
}

export function singleOrNull<T>(array: T[] | Set<T>): T | null {
if (array instanceof Set) {
if (array.size === 1) {
return array.values().next().value ?? null;
} else {
return null;
}
}
return array.length === 1 ? array[0] : null;
}

export namespace ListExt {
/**
* Create a list of the specified size with the specified value.
Expand Down
20 changes: 13 additions & 7 deletions monosketch-svelte/src/lib/mono/action-manager/action-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ import { type OneTimeActionType, OneTimeAction } from './one-time-actions';
* A class which gathers UI events and converts them into equivalent command.
*/
export class ActionManager {
private retainableActionFlow: Flow<RetainableActionType> = new Flow(RetainableActionType.IDLE);
private oneTimeActionFlow: Flow<OneTimeActionType> = new Flow(OneTimeAction.Idle);
private retainableActionMutableFlow: Flow<RetainableActionType> = new Flow(RetainableActionType.IDLE);
retainableActionFlow = this.retainableActionMutableFlow.distinctUntilChanged();

constructor(lifecycleOwner: LifecycleOwner, keyCommandFlow: Flow<KeyCommandType>) {
keyCommandFlow.distinctUntilChanged().observe(lifecycleOwner, this.onKeyEvent.bind(this));
private oneTimeActionMutableFlow: Flow<OneTimeActionType> = new Flow(OneTimeAction.Idle);
oneTimeActionFlow = this.oneTimeActionMutableFlow.immutable();

constructor(private lifecycleOwner: LifecycleOwner) {
}

observeKeyCommand(keyCommandFlow: Flow<KeyCommandType>) {
keyCommandFlow.distinctUntilChanged().observe(this.lifecycleOwner, this.onKeyEvent.bind(this));
}

private onKeyEvent(keyCommand: KeyCommandType) {
Expand Down Expand Up @@ -97,12 +103,12 @@ export class ActionManager {
}

setRetainableAction(actionType: RetainableActionType) {
this.retainableActionFlow.value = actionType;
this.retainableActionMutableFlow.value = actionType;
}

setOneTimeAction(actionType: OneTimeActionType) {
this.oneTimeActionFlow.value = actionType;
this.oneTimeActionFlow.value = OneTimeAction.Idle;
this.oneTimeActionMutableFlow.value = actionType;
this.oneTimeActionMutableFlow.value = OneTimeAction.Idle;
}

installDebugCommand() {
Expand Down
2 changes: 1 addition & 1 deletion monosketch-svelte/src/lib/mono/keycommand/keycommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const KeyCommandOptionsDefaults: KeyCommand = {
isRepeatable: false,
};

export const KeyCommands: KeyCommand[] = [
const KeyCommands: KeyCommand[] = [
{
...KeyCommandOptionsDefaults,
command: KeyCommandType.IDLE,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { mouseActionToContentMap, type MouseActionType } from './model';
import { MouseActionToContentMap, type MouseActionType } from './model';
import TooltipTarget from '../../modal/tooltip/TooltipTarget.svelte';
import SvgIcon from '../../common/SvgIcon.svelte';
Expand All @@ -12,10 +12,10 @@ function onClick() {
}
</script>

<TooltipTarget text="{mouseActionToContentMap[type].title}" offsetVertical="{8}">
<TooltipTarget text="{MouseActionToContentMap[type].title}" offsetVertical="{8}">
<button class="action" class:selected on:click="{onClick}">
<SvgIcon viewBoxSize="{24}" size="{21}">
<path d="{mouseActionToContentMap[type].iconPath}"></path>
<path d="{MouseActionToContentMap[type].iconPath}"></path>
</SvgIcon>
</button>
</TooltipTarget>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
<script lang="ts">
import MouseActionButton from './MouseActionButton.svelte';
import { MouseActionType, mouseActionTypes } from './model';
import {
MouseActionToContentMap,
MouseActionType,
mouseActionTypes,
RetainableActionTypeToMouseActionTypeMap
} from './model';
import { getContext, onDestroy, onMount } from "svelte";
import type { AppContext } from "$app/app-context";
import { APP_CONTEXT } from "$mono/common/constant";
import { LifecycleOwner } from "$libs/flow";
let selectedActionType: MouseActionType = MouseActionType.SELECTION;
const appContext = getContext<AppContext>(APP_CONTEXT);
const lifecycleOwner = new LifecycleOwner();
function onSelect(actionType: MouseActionType) {
selectedActionType = actionType;
appContext.actionManager.setRetainableAction(MouseActionToContentMap[actionType].retainableActionType);
}
onMount(() => {
lifecycleOwner.onStart();
appContext.actionManager.retainableActionFlow.observe(lifecycleOwner, (value) => {
selectedActionType = RetainableActionTypeToMouseActionTypeMap[value];
});
});
onDestroy(() => {
lifecycleOwner.onStop();
});
</script>

<div>
Expand Down
21 changes: 20 additions & 1 deletion monosketch-svelte/src/lib/ui/nav/mouseaction/model.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { RetainableActionType } from "$mono/action-manager/retainable-actions";

export enum MouseActionType {
SELECTION,
ADD_RECTANGLE,
Expand All @@ -12,22 +14,39 @@ export const mouseActionTypes = [
MouseActionType.ADD_LINE,
];

export const mouseActionToContentMap = {
interface MouseAction {
retainableActionType: RetainableActionType;
iconPath: string;
title: string;
}

export const MouseActionToContentMap: Record<MouseActionType, MouseAction> = {
[MouseActionType.SELECTION]: {
retainableActionType: RetainableActionType.IDLE,
iconPath: 'M7.436 20.61L7.275 3.914l12.296 11.29-7.165.235-4.97 5.168z',
title: 'Select (V)',
},
[MouseActionType.ADD_RECTANGLE]: {
retainableActionType: RetainableActionType.ADD_RECTANGLE,
iconPath: 'M22 19H2V5h20v14zM4 7v10h16V7z',
title: 'Rectangle (R)',
},
[MouseActionType.ADD_TEXT]: {
retainableActionType: RetainableActionType.ADD_TEXT,
iconPath:
'M5.635 21v-2h12.731v2zm3.27-4v-1.12h2.005V4.12H7.425l-.39.44v2.58h-1.4V3h12.731v4.14h-1.4V4.56l-.39-.44h-3.485v11.76h2.005V17z',
title: 'Text (T)',
},
[MouseActionType.ADD_LINE]: {
retainableActionType: RetainableActionType.ADD_LINE,
iconPath: 'M18 15v-2H6v2H0V9h6v2h12V9h6v6z',
title: 'Line (L)',
},
};

export const RetainableActionTypeToMouseActionTypeMap: Record<RetainableActionType, MouseActionType> = {
[RetainableActionType.IDLE]: MouseActionType.SELECTION,
[RetainableActionType.ADD_RECTANGLE]: MouseActionType.ADD_RECTANGLE,
[RetainableActionType.ADD_TEXT]: MouseActionType.ADD_TEXT,
[RetainableActionType.ADD_LINE]: MouseActionType.ADD_LINE,
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
export let label: string;
export let value: number;
export let minValue: number | null = null;
export let isEnabled = true;
export let isEnabled: boolean = true;
export let boundIncludesLabel = false;
</script>

Expand Down
44 changes: 44 additions & 0 deletions monosketch-svelte/src/lib/ui/pannel/shapetool/Footer.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!--
- Copyright (c) 2024, tuanchauict
-->
<script>
</script>

<div>
<a href="https://github.com/tuanchauict/MonoSketch">
<svg width="16" height="16" viewBox="0 0 32 32" fill="currentColor">
<path d="M16.288 0a16.291 16.291 0 0 0-5.148 31.747c.815.149 1.112-.353 1.112-.785 0-.387-.014-1.411-.022-2.771-4.531.985-5.487-2.183-5.487-2.183a4.315 4.315 0 0 0-1.809-2.383c-1.479-1.011.112-.99.112-.99a3.42 3.42 0 0 1 2.495 1.678 3.468 3.468 0 0 0 4.741 1.354 3.482 3.482 0 0 1 1.034-2.178c-3.617-.411-7.42-1.808-7.42-8.051a6.3 6.3 0 0 1 1.677-4.371 5.852 5.852 0 0 1 .16-4.311s1.367-.438 4.479 1.67a15.448 15.448 0 0 1 8.156 0c3.11-2.108 4.475-1.67 4.475-1.67a5.854 5.854 0 0 1 .163 4.311 6.286 6.286 0 0 1 1.674 4.371c0 6.258-3.809 7.635-7.438 8.038a3.889 3.889 0 0 1 1.106 3.017c0 2.178-.02 3.935-.02 4.469 0 .435.294.942 1.12.783A16.292 16.292 0 0 0 16.288 0z"></path>
</svg>
<span>GitHub</span>
</a>
</div>

<style lang="scss">
div {
padding: 10px 8px;
display: flex;
justify-content: center;
align-items: center;
}
a {
line-height: 14px;
font-size: 14px;
text-decoration: none;
color: var(--shapetool-footer-color);
display: flex;
align-items: center;
&:hover {
color: var(--shapetool-footer-hover-color);
}
&:active {
color: var(--shapetool-footer-active-color);
}
span {
margin-left: 6px;
}
}
</style>
88 changes: 44 additions & 44 deletions monosketch-svelte/src/lib/ui/pannel/shapetool/ShapeTool.svelte
Original file line number Diff line number Diff line change
@@ -1,65 +1,65 @@
<script lang="ts">
import ReorderTool from './reorder/ReorderTool.svelte';
import TransformTool from './transform/TransformTool.svelte';
import AppearanceTool from './appearance/AppearanceTool.svelte';
import TextTool from './text/TextTool.svelte';
import { getContext, onMount } from 'svelte';
import { AppContext } from '$app/app-context';
import { APP_CONTEXT } from '$mono/common/constant';
import { LifecycleOwner } from 'lib/libs/flow';
import { getContext, onDestroy, onMount, setContext } from 'svelte';
import { AppContext } from '$app/app-context';
import { APP_CONTEXT } from '$mono/common/constant';
import { Flow, LifecycleOwner } from 'lib/libs/flow';
import Footer from "./Footer.svelte";
import ShapeToolBody from "$ui/pannel/shapetool/ShapeToolBody.svelte";
import { ShapeToolViewModel } from "$ui/pannel/shapetool/viewmodel/shape-tool-viewmodel";
import { SHAPE_TOOL_VIEWMODEL } from "$ui/pannel/shapetool/constants.js";
const appContext = getContext<AppContext>(APP_CONTEXT);
const lifecycleOwner = new LifecycleOwner();
const appContext = getContext<AppContext>(APP_CONTEXT);
const lifecycleOwner = new LifecycleOwner();
let isVisible = true;
setContext(SHAPE_TOOL_VIEWMODEL, new ShapeToolViewModel(
new Flow(new Set()), // TODO: Replace with real flow
appContext.shapeManager.versionFlow,
appContext.actionManager
));
onMount(() => {
lifecycleOwner.onStart();
let isVisible = true;
appContext.appUiStateManager.shapeFormatPanelVisibilityFlow.observe(lifecycleOwner, (value) => {
isVisible = value;
onMount(() => {
lifecycleOwner.onStart();
appContext.appUiStateManager.shapeFormatPanelVisibilityFlow.observe(lifecycleOwner, (value) => {
isVisible = value;
});
});
onDestroy(() => {
lifecycleOwner.onStop();
});
});
</script>

{#if isVisible}
<div class="container">
<div class="body">
<ReorderTool />
<TransformTool />
<AppearanceTool />
<TextTool />
<ShapeToolBody/>
</div>
<div class="footer">Hello</div>
<Footer/>
</div>
{/if}

<style lang="scss">
@import '$style/variables.scss';
.container {
display: flex;
flex-direction: column;
height: 100%;
@import '$style/variables.scss';
border-left: 1px solid var(--shapetool-main-divider-color);
background: var(--shapetool-bg-color);
.container {
display: flex;
flex-direction: column;
height: 100%;
font-family: $uiTextFont;
font-size: 12px;
}
border-left: 1px solid var(--shapetool-main-divider-color);
background: var(--shapetool-bg-color);
.body {
height: 100%;
overflow-y: scroll;
display: flex;
flex-direction: column;
}
font-family: $uiTextFont;
font-size: 12px;
}
.footer {
padding: 10px 8px;
display: flex;
justify-content: center;
align-items: center;
}
.body {
height: 100%;
overflow-y: scroll;
display: flex;
flex-direction: column;
}
</style>
Loading

0 comments on commit b85b7e8

Please sign in to comment.