Files
Graphite/frontend/src/components/widgets/inputs/SwatchPairInput.vue
Christian Authmann 448e72fe02 Rework wasm initialization and reduce global state (#379)
* wasm: do the async initialization only once

This allows the rest of the app to access wasm synchronously.

This allows removing of a global.

* provide the wasm via vue provide/inject.

There's still code directly accessing the wasm. That will be changed later.

* MenuBarInput: use injected wasm instead of the global instance

* Let the App handle event listeners

* move stateful modules into state/

* state/fullscreen: create per instance

* App: load the initial document list on mount.
This got lost a few commits ago. Now it's back.

* state/dialog: create per instance

* util/input: remove dependency on global dialog instance

* state/documents: create per instance

* reponse-handler: move into EditorWasm

* comingSoon: move into dialog

* wasm: allow instantiating multiple editors

* input handlers: do not look at canvases outside the mounted App

* input: listen on the container instead of the window when possible

* - removed proxy from wasm-loader
- integrated with js-dispatcher
- state functions to classes
- integrated some upstream changes

* fix errors caused by merge

* Getting closer:
- added global state to track all instances
- fix fullscreen close trigger
- wasm-loader is statefull
- panic across instanes

* - fix outline while using editor
- removed circular import rule
- added editorInstance to js message constructor

* - changed input handler to a class
- still need a better way of handeling it in App.vue

* - fixed single instance of inputManager to weakmap

* - fix no-explicit-any in a few places
- removed global state from input.ts

* simplified two long lines

* removed global state

* removed $data from App

* add mut self to functions in api.rs

* Update Workspace.vue

remove outdated import

* fixed missing import

* Changes throughout code review; note this causes some bugs to be fixed in a later commit

* PR review round 1

* - fix coming soon bugs
- changed folder structure

* moved declaration to .d.ts

* - changed from classes to functions
- moved decs back to app.vue

* removed need to export js function to rust

* changed folder structure

* fixed indentation breaking multiline strings

* Fix eslint rule to whitelist @/../

* Simplify strip-indents implementation

* replace type assertions with better annotations or proper runtime checks

* Small tweaks and code rearranging improvements after second code review pass

* maybe fix mouse events

* Add back preventDefault for mouse scroll

* code review round 2

* Comment improvements

* -removed runtime checks
- fixed layers not showing

* - extened proxy to cover classes
- stopped multiple panics from logging
- Stop wasm-bindgen from mut ref counting our struct

* cleaned up messageConstructors exports

* Fix input and fullscreen regressions

Co-authored-by: Max Fisher <maxmfishernj@gmail.com>
Co-authored-by: mfish33 <32677537+mfish33@users.noreply.github.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
2021-12-19 22:37:19 -08:00

154 lines
4.5 KiB
Vue

<template>
<div class="swatch-pair">
<div class="secondary swatch">
<button @click="clickSecondarySwatch" ref="secondaryButton" data-hover-menu-spawner></button>
<FloatingMenu :type="MenuType.Popover" :direction="MenuDirection.Right" horizontal ref="secondarySwatchFloatingMenu">
<ColorPicker @update:color="secondaryColorChanged" :color="secondaryColor" />
</FloatingMenu>
</div>
<div class="primary swatch">
<button @click="clickPrimarySwatch" ref="primaryButton" data-hover-menu-spawner></button>
<FloatingMenu :type="MenuType.Popover" :direction="MenuDirection.Right" horizontal ref="primarySwatchFloatingMenu">
<ColorPicker @update:color="primaryColorChanged" :color="primaryColor" />
</FloatingMenu>
</div>
</div>
</template>
<style lang="scss">
.swatch-pair {
display: flex;
// Reversed order of elements paired with `column-reverse` allows primary to overlap secondary without relying on `z-index`
flex-direction: column-reverse;
.swatch {
width: 28px;
height: 28px;
margin: 0 2px;
position: relative;
button {
--swatch-color: #ffffff;
width: 100%;
height: 100%;
border-radius: 50%;
border: 2px var(--color-7-middlegray) solid;
box-shadow: 0 0 0 2px var(--color-3-darkgray);
margin: 0;
padding: 0;
box-sizing: border-box;
outline: none;
background: linear-gradient(45deg, #cccccc 25%, transparent 25%, transparent 75%, #cccccc 75%), linear-gradient(45deg, #cccccc 25%, transparent 25%, transparent 75%, #cccccc 75%),
linear-gradient(#ffffff, #ffffff);
background-size: 16px 16px;
background-position: 0 0, 8px 8px;
overflow: hidden;
&::before {
content: "";
display: block;
width: 100%;
height: 100%;
background: var(--swatch-color);
}
}
.floating-menu {
top: 50%;
right: -2px;
}
&.primary {
margin-bottom: -8px;
}
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import { rgbToDecimalRgb, RGB } from "@/utilities/color";
import ColorPicker from "@/components/widgets/floating-menus/ColorPicker.vue";
import FloatingMenu, { MenuDirection, MenuType } from "@/components/widgets/floating-menus/FloatingMenu.vue";
import { UpdateWorkingColors } from "@/dispatcher/js-messages";
export default defineComponent({
inject: ["editor"],
components: {
FloatingMenu,
ColorPicker,
},
props: {},
methods: {
clickPrimarySwatch() {
this.getRef<typeof FloatingMenu>("primarySwatchFloatingMenu").setOpen();
this.getRef<typeof FloatingMenu>("secondarySwatchFloatingMenu").setClosed();
},
clickSecondarySwatch() {
this.getRef<typeof FloatingMenu>("secondarySwatchFloatingMenu").setOpen();
this.getRef<typeof FloatingMenu>("primarySwatchFloatingMenu").setClosed();
},
getRef<T>(name: string) {
return this.$refs[name] as T;
},
primaryColorChanged(color: RGB) {
this.primaryColor = color;
this.updatePrimaryColor();
},
secondaryColorChanged(color: RGB) {
this.secondaryColor = color;
this.updateSecondaryColor();
},
async updatePrimaryColor() {
let color = this.primaryColor;
const button = this.getRef<HTMLButtonElement>("primaryButton");
button.style.setProperty("--swatch-color", `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`);
color = rgbToDecimalRgb(this.primaryColor);
this.editor.instance.update_primary_color(color.r, color.g, color.b, color.a);
},
async updateSecondaryColor() {
let color = this.secondaryColor;
const button = this.getRef<HTMLButtonElement>("secondaryButton");
button.style.setProperty("--swatch-color", `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`);
color = rgbToDecimalRgb(this.secondaryColor);
this.editor.instance.update_secondary_color(color.r, color.g, color.b, color.a);
},
},
data() {
return {
MenuDirection,
MenuType,
primaryColor: { r: 0, g: 0, b: 0, a: 1 },
secondaryColor: { r: 255, g: 255, b: 255, a: 1 },
};
},
mounted() {
this.editor.dispatcher.subscribeJsMessage(UpdateWorkingColors, (updateWorkingColors) => {
const { primary, secondary } = updateWorkingColors;
this.primaryColor = primary.toRgba();
this.secondaryColor = secondary.toRgba();
const primaryButton = this.getRef<HTMLButtonElement>("primaryButton");
primaryButton.style.setProperty("--swatch-color", primary.toRgbaCSS());
const secondaryButton = this.getRef<HTMLButtonElement>("secondaryButton");
secondaryButton.style.setProperty("--swatch-color", secondary.toRgbaCSS());
});
this.updatePrimaryColor();
this.updateSecondaryColor();
},
});
</script>