Reorganize Vue components and add documentation explaining each folder

This commit is contained in:
Keavon Chambers
2022-05-23 19:03:34 -07:00
parent 5650a87465
commit e4e37cca7b
23 changed files with 46 additions and 28 deletions

View File

@@ -22,7 +22,7 @@ import { defineComponent } from "vue";
import LayoutCol from "@/components/layout/LayoutCol.vue";
import StatusBar from "@/components/window/status-bar/StatusBar.vue";
import TitleBar from "@/components/window/title-bar/TitleBar.vue";
import Workspace from "@/components/workspace/Workspace.vue";
import Workspace from "@/components/window/workspace/Workspace.vue";
export type ApplicationPlatform = "Windows" | "Mac" | "Linux" | "Web";

View File

@@ -47,8 +47,8 @@ import { defineComponent } from "vue";
import { HintData, UpdateInputHints } from "@/wasm-communication/messages";
import LayoutRow from "@/components/layout/LayoutRow.vue";
import Separator from "@/components/widgets/labels/Separator.vue";
import UserInputLabel from "@/components/widgets/labels/UserInputLabel.vue";
import Separator from "@/components/widgets/separators/Separator.vue";
export default defineComponent({
inject: ["editor"],

View File

@@ -0,0 +1,186 @@
<template>
<LayoutCol class="panel">
<LayoutRow class="tab-bar" data-tab-bar :class="{ 'min-widths': tabMinWidths }">
<LayoutRow class="tab-group" :scrollableX="true">
<LayoutRow
class="tab"
:class="{ active: tabIndex === tabActiveIndex }"
data-tab
v-for="(tabLabel, tabIndex) in tabLabels"
:key="tabIndex"
@click="(e) => (e?.stopPropagation(), clickAction?.(tabIndex))"
@click.middle="(e) => (e?.stopPropagation(), closeAction?.(tabIndex))"
>
<span>{{ tabLabel }}</span>
<IconButton :action="(e) => (e?.stopPropagation(), closeAction?.(tabIndex))" :icon="'CloseX'" :size="16" v-if="tabCloseButtons" />
</LayoutRow>
</LayoutRow>
<PopoverButton :icon="'VerticalEllipsis'">
<h3>Panel Options</h3>
<p>The contents of this popover menu are coming soon</p>
</PopoverButton>
</LayoutRow>
<LayoutCol class="panel-body">
<component :is="panelType" />
</LayoutCol>
</LayoutCol>
</template>
<style lang="scss">
.panel {
background: var(--color-1-nearblack);
border-radius: 6px;
overflow: hidden;
.tab-bar {
height: 28px;
min-height: auto;
&.min-widths .tab-group .tab {
min-width: 120px;
max-width: 360px;
}
.tab-group {
flex: 1 1 100%;
position: relative;
// This always hangs out at the end of the last tab, providing 16px (15px plus the 1px reserved for the separator line) to the right of the tabs.
// When the last tab is selected, its bottom rounded fillet adds 16px to the width, which stretches the scrollbar width allocation in only that situation.
// This pseudo-element ensures we always reserve that space to prevent the scrollbar from jumping when the last tab is selected.
// There is unfortunately no apparent way to remove that 16px gap from the end of the scroll container, since negative margin does not reduce the scrollbar allocation.
&::after {
content: "";
width: 15px;
flex: 0 0 auto;
}
.tab {
flex: 0 1 auto;
height: 100%;
padding: 0 8px;
align-items: center;
position: relative;
&.active {
background: var(--color-3-darkgray);
border-radius: 6px 6px 0 0;
position: relative;
&:not(:first-child)::before,
&::after {
content: "";
width: 16px;
height: 8px;
position: absolute;
bottom: 0;
}
&:not(:first-child)::before {
left: -16px;
border-bottom-right-radius: 8px;
box-shadow: 8px 0 0 0 var(--color-3-darkgray);
}
&::after {
right: -16px;
border-bottom-left-radius: 8px;
box-shadow: -8px 0 0 0 var(--color-3-darkgray);
}
}
span {
flex: 1 1 100%;
overflow-x: hidden;
white-space: nowrap;
text-overflow: ellipsis;
// Height and line-height required because https://stackoverflow.com/a/21611191/775283
height: 100%;
line-height: 28px;
}
.icon-button {
margin-left: 8px;
}
& + .tab {
margin-left: 1px;
}
&:not(.active) + .tab:not(.active)::before {
content: "";
position: absolute;
left: -1px;
width: 1px;
height: 16px;
background: var(--color-4-dimgray);
}
&:last-of-type {
margin-right: 1px;
&:not(.active)::after {
content: "";
position: absolute;
right: -1px;
width: 1px;
height: 16px;
background: var(--color-4-dimgray);
}
}
}
}
.popover-button {
margin: 2px 4px;
}
}
.panel-body {
background: var(--color-3-darkgray);
flex: 1 1 100%;
flex-direction: column;
min-height: 0;
}
}
</style>
<script lang="ts">
import { defineComponent, PropType } from "vue";
import LayoutCol from "@/components/layout/LayoutCol.vue";
import LayoutRow from "@/components/layout/LayoutRow.vue";
import Document from "@/components/panels/Document.vue";
import LayerTree from "@/components/panels/LayerTree.vue";
import NodeGraph from "@/components/panels/NodeGraph.vue";
import Properties from "@/components/panels/Properties.vue";
import IconButton from "@/components/widgets/buttons/IconButton.vue";
import PopoverButton from "@/components/widgets/buttons/PopoverButton.vue";
const panelComponents = {
Document,
Properties,
LayerTree,
NodeGraph,
IconButton,
PopoverButton,
};
type PanelTypes = keyof typeof panelComponents;
export default defineComponent({
props: {
tabMinWidths: { type: Boolean as PropType<boolean>, default: false },
tabCloseButtons: { type: Boolean as PropType<boolean>, default: false },
tabLabels: { type: Array as PropType<string[]>, required: true },
tabActiveIndex: { type: Number as PropType<number>, required: true },
panelType: { type: String as PropType<PanelTypes>, required: true },
clickAction: { type: Function as PropType<(index: number) => void>, required: false },
closeAction: { type: Function as PropType<(index: number) => void>, required: false },
},
components: {
LayoutCol,
LayoutRow,
...panelComponents,
},
});
</script>

View File

@@ -0,0 +1,146 @@
<template>
<LayoutRow class="workspace" data-workspace>
<LayoutRow class="workspace-grid-subdivision">
<LayoutCol class="workspace-grid-subdivision">
<LayoutRow class="workspace-grid-subdivision">
<Panel
:panelType="'Document'"
:tabCloseButtons="true"
:tabMinWidths="true"
:tabLabels="portfolio.state.documents.map((doc) => doc.displayName)"
:clickAction="(tabIndex) => editor.instance.select_document(portfolio.state.documents[tabIndex].id)"
:closeAction="(tabIndex) => editor.instance.close_document_with_confirmation(portfolio.state.documents[tabIndex].id)"
:tabActiveIndex="portfolio.state.activeDocumentIndex"
ref="documentsPanel"
/>
</LayoutRow>
<LayoutRow class="workspace-grid-resize-gutter" @pointerdown="(e) => resizePanel(e)" v-if="nodeGraphVisible"></LayoutRow>
<LayoutRow class="workspace-grid-subdivision" v-if="nodeGraphVisible">
<Panel :panelType="'NodeGraph'" :tabLabels="['Node Graph']" :tabActiveIndex="0" />
</LayoutRow>
</LayoutCol>
<LayoutCol class="workspace-grid-resize-gutter" @pointerdown="(e) => resizePanel(e)"></LayoutCol>
<LayoutCol class="workspace-grid-subdivision" style="flex-grow: 0.17">
<LayoutRow class="workspace-grid-subdivision" style="flex-grow: 402">
<Panel :panelType="'Properties'" :tabLabels="['Properties']" :tabActiveIndex="0" />
</LayoutRow>
<LayoutRow class="workspace-grid-resize-gutter" @pointerdown="(e) => resizePanel(e)"></LayoutRow>
<LayoutRow class="workspace-grid-subdivision" style="flex-grow: 590">
<Panel :panelType="'LayerTree'" :tabLabels="['Layer Tree']" :tabActiveIndex="0" />
</LayoutRow>
</LayoutCol>
</LayoutRow>
<DialogModal v-if="dialog.state.visible" />
</LayoutRow>
</template>
<style lang="scss">
.workspace {
position: relative;
flex: 1 1 100%;
.workspace-grid-subdivision {
min-height: 28px;
flex: 1 1 0;
&.folded {
flex-grow: 0;
height: 0;
}
}
.workspace-grid-resize-gutter {
flex: 0 0 4px;
&.layout-row {
cursor: ns-resize;
}
&.layout-col {
cursor: ew-resize;
}
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import DialogModal from "@/components/floating-menus/DialogModal.vue";
import LayoutCol from "@/components/layout/LayoutCol.vue";
import LayoutRow from "@/components/layout/LayoutRow.vue";
import Panel from "@/components/window/workspace/Panel.vue";
const MIN_PANEL_SIZE = 100;
export default defineComponent({
inject: ["workspace", "portfolio", "dialog", "editor"],
components: {
LayoutRow,
LayoutCol,
Panel,
DialogModal,
},
computed: {
activeDocumentIndex() {
return this.portfolio.state.activeDocumentIndex;
},
nodeGraphVisible() {
return this.workspace.state.nodeGraphVisible;
},
},
methods: {
resizePanel(event: PointerEvent) {
const gutter = event.target as HTMLElement;
const nextSibling = gutter.nextElementSibling as HTMLElement;
const previousSibling = gutter.previousElementSibling as HTMLElement;
// Are we resizing horizontally?
const horizontal = gutter.classList.contains("layout-col");
// Get the current size in px of the panels being resized
const nextSiblingSize = horizontal ? nextSibling.getBoundingClientRect().width : nextSibling.getBoundingClientRect().height;
const previousSiblingSize = horizontal ? previousSibling.getBoundingClientRect().width : previousSibling.getBoundingClientRect().height;
// Prevent cursor flicker as mouse temporarily leaves the gutter
gutter.setPointerCapture(event.pointerId);
const mouseStart = horizontal ? event.clientX : event.clientY;
function updatePosition(event: PointerEvent): void {
const mouseCurrent = horizontal ? event.clientX : event.clientY;
let mouseDelta = mouseStart - mouseCurrent;
mouseDelta = Math.max(nextSiblingSize + mouseDelta, MIN_PANEL_SIZE) - nextSiblingSize;
mouseDelta = previousSiblingSize - Math.max(previousSiblingSize - mouseDelta, MIN_PANEL_SIZE);
nextSibling.style.flexGrow = (nextSiblingSize + mouseDelta).toString();
previousSibling.style.flexGrow = (previousSiblingSize - mouseDelta).toString();
window.dispatchEvent(new CustomEvent("resize", { detail: {} }));
}
function cleanup(event: PointerEvent): void {
gutter.releasePointerCapture(event.pointerId);
document.removeEventListener("pointermove", updatePosition);
document.removeEventListener("pointerleave", cleanup);
document.removeEventListener("pointerup", cleanup);
}
document.addEventListener("pointermove", updatePosition);
document.addEventListener("pointerleave", cleanup);
document.addEventListener("pointerup", cleanup);
},
},
watch: {
activeDocumentIndex(newIndex: number) {
this.$nextTick(() => {
const documentsPanel = this.$refs.documentsPanel as typeof Panel;
const newActiveTab = documentsPanel.$el.querySelectorAll("[data-tab-bar] [data-tab]")[newIndex];
newActiveTab.scrollIntoView();
});
},
},
});
</script>