Welcome screen, refactor to allow zero documents, and add TS typing to widgets (#702)

* unfinished implementation

* Add frontend for the empty panel screen

* Add an icon for Folder based on NodeFolder

* fixed messages causing peicees of ui not to render on new document

* Standardize nextTick syntax

* WIP generisization of component subscriptions (not compiling yet)

* Fix crash when loading font and there is no active document

* Only advertise tool actions with a document

* Fix failure to create new document

* Initalise the properties panel

* Fix highlight tab, canvas jump, warns and layer tree

* Fix tests

* Possibly fix some things?

* Move WorkingColors layout definition to backend

* Standardize action macro formatting

* Provide typing for widgets in TS/Vue and associated cleanup

* Fix viewport positioning initialization

* Fix menu bar init at startup not document creation

* Fix no viewport bounds bug

* Change !=0 to >0

* Simplify the init system

Closes #656

Co-authored-by: Keavon Chambers <keavon@keavon.com>
Co-authored-by: 0hypercube <0hypercube@gmail.com>
This commit is contained in:
mfish33
2022-07-22 16:09:13 -06:00
committed by Keavon Chambers
co-authored by Keavon Chambers 0hypercube
parent b4b667ded6
commit a0c22d20b6
77 changed files with 1859 additions and 1136 deletions
@@ -21,7 +21,36 @@
</PopoverButton>
</LayoutRow>
<LayoutCol class="panel-body">
<component :is="panelType" />
<component :is="panelType" v-if="panelType" />
<LayoutCol class="empty-panel" v-else>
<LayoutCol class="content">
<LayoutRow class="logotype">
<IconLabel :icon="'GraphiteLogotypeSolid'" />
</LayoutRow>
<LayoutRow class="actions">
<LayoutCol>
<IconButton :action="() => newDocument()" :icon="'File'" :size="24" />
<IconButton :action="() => openDocument()" :icon="'Folder'" :size="24" />
</LayoutCol>
<LayoutCol>
<Separator :type="'Related'" />
<Separator :type="'Related'" />
</LayoutCol>
<LayoutCol>
<TextLabel>New Document:</TextLabel>
<TextLabel>Open Document:</TextLabel>
</LayoutCol>
<LayoutCol>
<Separator :type="'Unrelated'" />
<Separator :type="'Unrelated'" />
</LayoutCol>
<LayoutCol>
<UserInputLabel :inputKeys="[['KeyControl', 'KeyN']]" />
<UserInputLabel :inputKeys="[['KeyControl', 'KeyO']]" />
</LayoutCol>
</LayoutRow>
</LayoutCol>
</LayoutCol>
</LayoutCol>
</LayoutCol>
</template>
@@ -141,6 +170,45 @@
flex: 1 1 100%;
flex-direction: column;
min-height: 0;
.empty-panel {
background: var(--color-2-mildblack);
margin: 4px;
border-radius: 2px;
justify-content: center;
.content {
flex: 0 0 auto;
align-items: center;
.logotype {
margin-bottom: 40px;
svg {
width: auto;
height: 120px;
}
}
.actions {
> div {
gap: 8px;
> * {
height: 24px;
}
.text-label {
line-height: 24px;
}
.user-input-label {
margin: 0;
}
}
}
}
}
}
}
</style>
@@ -156,6 +224,10 @@ 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";
import IconLabel from "@/components/widgets/labels/IconLabel.vue";
import Separator from "@/components/widgets/labels/Separator.vue";
import TextLabel from "@/components/widgets/labels/TextLabel.vue";
import UserInputLabel from "@/components/widgets/labels/UserInputLabel.vue";
const panelComponents = {
Document,
@@ -168,18 +240,31 @@ const panelComponents = {
type PanelTypes = keyof typeof panelComponents;
export default defineComponent({
inject: ["editor"],
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 },
panelType: { type: String as PropType<PanelTypes>, required: false },
clickAction: { type: Function as PropType<(index: number) => void>, required: false },
closeAction: { type: Function as PropType<(index: number) => void>, required: false },
},
methods: {
newDocument() {
this.editor.instance.new_document_dialog();
},
openDocument() {
this.editor.instance.open_file_upload();
},
},
components: {
LayoutCol,
LayoutRow,
IconLabel,
TextLabel,
UserInputLabel,
Separator,
...panelComponents,
},
});
@@ -4,7 +4,7 @@
<LayoutCol class="workspace-grid-subdivision">
<LayoutRow class="workspace-grid-subdivision">
<Panel
:panelType="'Document'"
:panelType="portfolio.state.documents.length > 0 ? 'Document' : undefined"
:tabCloseButtons="true"
:tabMinWidths="true"
:tabLabels="portfolio.state.documents.map((doc) => doc.displayName)"
@@ -64,7 +64,7 @@
</style>
<script lang="ts">
import { defineComponent } from "vue";
import { defineComponent, nextTick } from "vue";
import DialogModal from "@/components/floating-menus/DialogModal.vue";
import LayoutCol from "@/components/layout/LayoutCol.vue";
@@ -117,7 +117,7 @@ export default defineComponent({
nextSibling.style.flexGrow = (nextSiblingSize + mouseDelta).toString();
previousSibling.style.flexGrow = (previousSiblingSize - mouseDelta).toString();
window.dispatchEvent(new CustomEvent("resize", { detail: {} }));
window.dispatchEvent(new CustomEvent("resize"));
}
function cleanup(event: PointerEvent): void {
@@ -134,12 +134,12 @@ export default defineComponent({
},
},
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();
});
async activeDocumentIndex(newIndex: number) {
await nextTick();
const documentsPanel = this.$refs.documentsPanel as typeof Panel;
const newActiveTab = documentsPanel.$el.querySelectorAll("[data-tab-bar] [data-tab]")[newIndex];
newActiveTab.scrollIntoView();
},
},
});