Rename project structure with /core and /client

This commit is contained in:
Keavon Chambers
2021-03-22 11:21:15 -07:00
parent 18a8442b0e
commit 7bfb04a99a
64 changed files with 63 additions and 43 deletions

View File

@@ -0,0 +1,19 @@
<template>
<div :class="['layout-col']">
<slot></slot>
</div>
</template>
<style lang="scss">
.layout-col {
display: flex;
flex-direction: column;
flex-grow: 1;
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({});
</script>

View File

@@ -0,0 +1,19 @@
<template>
<div :class="['layout-row']">
<slot></slot>
</div>
</template>
<style lang="scss">
.layout-row {
display: flex;
flex-direction: row;
flex-grow: 1;
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({});
</script>

View File

@@ -0,0 +1,195 @@
<template>
<div class="panel">
<div class="tab-bar" :class="{ 'min-widths': tabMinWidths }">
<div class="tab-group">
<div class="tab" :class="{ active: tabIndex === tabActiveIndex }" v-for="(tabLabel, tabIndex) in tabLabels" :key="tabLabel">
<span>{{tabLabel}}</span>
<button v-if="tabCloseButtons">
<svg width="16" height="16" viewBox="0 0 16 16">
<polygon points="12,5 11,4 8,7 5,4 4,5 7,8 4,11 5,12 8,9 11,12 12,11 9,8" />
</svg>
</button>
</div>
</div>
<div class="panel-options-ellipsis">
<svg viewBox="0 0 16 24">
<circle cx="8" cy="8" r="1.5" />
<circle cx="8" cy="12" r="1.5" />
<circle cx="8" cy="16" r="1.5" />
</svg>
</div>
</div>
<div class="panel-content">
<component :is="panelType" />
</div>
</div>
</template>
<style lang="scss">
.panel {
background: #111;
border-radius: 8px;
flex-grow: 1;
display: flex;
flex-direction: column;
overflow: hidden;
.tab-bar {
height: 28px;
display: flex;
flex-direction: row;
&.min-widths .tab-group .tab {
min-width: 120px;
max-width: 360px;
}
.tab-group {
flex: 1 1 100%;
display: flex;
flex-direction: row;
overflow: hidden;
.tab {
height: 100%;
padding: 0 10px;
display: flex;
align-items: center;
position: relative;
&.active {
background: #333;
border-radius: 8px 8px 0 0;
position: relative;
&::before, &::after {
content: "";
width: 16px;
height: 8px;
position: absolute;
bottom: 0;
box-shadow: #333;
}
&::before {
left: -16px;
border-bottom-right-radius: 8px;
box-shadow: 8px 0 0 0 #333;
}
&::after {
right: -16px;
border-bottom-left-radius: 8px;
box-shadow: -8px 0 0 0 #333;
}
}
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;
}
button {
flex: 0 0 auto;
outline: none;
border: none;
padding: 0;
width: 16px;
height: 16px;
background: none;
color: #ddd;
font-weight: bold;
font-size: 10px;
border-radius: 2px;
margin-left: 8px;
fill: #ddd;
&:hover {
background: #555;
color: white;
fill: white;
}
}
&:not(.active) + .tab:not(.active) {
margin-left: 1px;
&::before {
content: "";
position: absolute;
left: -1px;
width: 1px;
height: 16px;
background: #444;
}
}
&:last-of-type:not(.active) {
margin-right: 1px;
&::after {
content: "";
position: absolute;
right: -1px;
width: 1px;
height: 16px;
background: #444;
}
}
}
}
.panel-options-ellipsis {
width: 16px;
height: 24px;
margin: 2px 4px;
svg {
width: 16px;
height: 24px;
border-radius: 2px;
fill: #ddd;
}
&:hover svg {
background: #555;
fill: #fff;
}
}
}
.panel-content {
background: #333;
flex-grow: 1;
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import Viewport from "../panels/ViewportPanel.vue";
import Properties from "../panels/PropertiesPanel.vue";
import Layers from "../panels/LayersPanel.vue";
import Minimap from "../panels/MinimapPanel.vue";
export default defineComponent({
components: {
Viewport,
Properties,
Layers,
Minimap,
},
props: {
tabMinWidths: { type: Boolean, default: false },
tabCloseButtons: { type: Boolean, default: false },
tabLabels: { type: Array, required: true },
tabActiveIndex: { type: Number, required: true },
panelType: { type: String, required: true },
},
});
</script>

View File

@@ -0,0 +1,54 @@
<template>
<LayoutRow class="dockable-grid-subdivision">
<LayoutCol class="dockable-grid-subdivision" style="flex-grow: 1597;">
<DockablePanel :panelType="'Viewport'" :tabCloseButtons="true" :tabMinWidths="true" :tabLabels="['X-35B Over Death Valley*', 'Document 2', 'Document 3', 'Document 4', 'Document 5']" :tabActiveIndex="0" />
</LayoutCol>
<LayoutCol class="dockable-grid-resize-gutter"></LayoutCol>
<LayoutCol class="dockable-grid-subdivision" style="flex-grow: 319;">
<LayoutRow class="dockable-grid-subdivision">
<DockablePanel :panelType="'Properties'" :tabLabels="['Properties', 'Typography', 'Colors']" :tabActiveIndex="0" />
</LayoutRow>
<LayoutRow class="dockable-grid-resize-gutter"></LayoutRow>
<LayoutRow class="dockable-grid-subdivision">
<DockablePanel :panelType="'Layers'" :tabLabels="['Layers']" :tabActiveIndex="0" />
</LayoutRow>
<LayoutRow class="dockable-grid-resize-gutter"></LayoutRow>
<LayoutRow class="dockable-grid-subdivision" style="flex-grow: 0; height: 0;">
<DockablePanel :panelType="'Minimap'" :tabLabels="['Minimap', 'Brushes', 'Links']" :tabActiveIndex="0" />
</LayoutRow>
</LayoutCol>
</LayoutRow>
</template>
<style lang="scss">
.dockable-grid-subdivision {
min-height: 28px;
}
.dockable-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 LayoutRow from "../layout/LayoutRow.vue";
import LayoutCol from "../layout/LayoutCol.vue";
import DockablePanel from "./DockablePanel.vue";
export default defineComponent({
components: {
LayoutRow,
LayoutCol,
DockablePanel,
},
});
</script>

View File

@@ -0,0 +1,21 @@
<template>
<div>
</div>
</template>
<style lang="scss">
</style>
<script lang="ts">
import { defineComponent } from "vue";
// import LayoutRow from "../layout/LayoutRow.vue";
// import LayoutCol from "../layout/LayoutCol.vue";
export default defineComponent({
components: {
},
props: {
},
});
</script>

View File

@@ -0,0 +1,21 @@
<template>
<div>
</div>
</template>
<style lang="scss">
</style>
<script lang="ts">
import { defineComponent } from "vue";
// import LayoutRow from "../layout/LayoutRow.vue";
// import LayoutCol from "../layout/LayoutCol.vue";
export default defineComponent({
components: {
},
props: {
},
});
</script>

View File

@@ -0,0 +1,21 @@
<template>
<div>
</div>
</template>
<style lang="scss">
</style>
<script lang="ts">
import { defineComponent } from "vue";
// import LayoutRow from "../layout/LayoutRow.vue";
// import LayoutCol from "../layout/LayoutCol.vue";
export default defineComponent({
components: {
},
props: {
},
});
</script>

View File

@@ -0,0 +1,81 @@
<template>
<LayoutCol :class="'viewport'">
<LayoutRow :class="'options-bar'">
<div class="left side">
<!-- <span class="label">Select</span>
<div class="divider"></div> -->
</div>
<div class="spacer"></div>
<div class="right side">
<!-- <span class="label">Layer 1</span> -->
</div>
</LayoutRow>
<LayoutRow :class="'tools-and-viewport'">
<LayoutCol :class="'tools'"></LayoutCol>
<LayoutCol :class="'viewport-container'"></LayoutCol>
</LayoutRow>
</LayoutCol>
</template>
<style lang="scss">
.viewport {
height: 100%;
.options-bar {
flex: 0 0 32px;
.side {
height: 100%;
flex: 0 1 auto;
display: flex;
align-items: center;
margin: 0 4px;
> * {
margin: 0 4px;
}
.label {
white-space: nowrap;
font-weight: bold;
}
.divider {
width: 1px;
height: 24px;
background: #888;
}
}
.spacer {
flex: 1 1 100%;
}
}
.tools-and-viewport {
.tools {
flex: 0 0 32px;
}
.viewport-container {
background: #111;
flex: 1 1 100%;
}
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import LayoutRow from "../layout/LayoutRow.vue";
import LayoutCol from "../layout/LayoutCol.vue";
export default defineComponent({
components: {
LayoutRow,
LayoutCol,
},
props: {
},
});
</script>

View File

@@ -0,0 +1,66 @@
<template>
<LayoutCol class="main-window">
<LayoutRow :class="'title-bar'">
<TitleBar :platform="platform" :maximized="maximized" />
</LayoutRow>
<LayoutRow :class="'panel-container'">
<PanelArea />
</LayoutRow>
<LayoutRow :class="'footer-bar'">
<FooterBar />
</LayoutRow>
</LayoutCol>
</template>
<style lang="scss">
.main-window {
height: 100%;
}
.title-bar {
height: 28px;
flex: 0 0 auto;
}
.panel-container {
flex: 1 1 100%;
height: 100%;
}
.footer-bar {
height: 24px;
flex: 0 0 auto;
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import LayoutRow from "../layout/LayoutRow.vue";
import LayoutCol from "../layout/LayoutCol.vue";
import PanelArea from "../panel-system/PanelArea.vue";
import TitleBar from "./title-bar/TitleBar.vue";
import FooterBar from "./footer-bar/FooterBar.vue";
export enum ApplicationPlatform {
"Windows" = "Windows",
"Mac" = "Mac",
"Linux" = "Linux",
"Web" = "Web",
}
export default defineComponent({
components: {
LayoutRow,
LayoutCol,
TitleBar,
PanelArea,
FooterBar,
},
data() {
return {
platform: ApplicationPlatform.Windows,
maximized: true,
};
},
});
</script>

View File

@@ -0,0 +1,73 @@
<template>
<div class="hint-area footer-area">
<InputHint :inputMouse="'LMB'">Select Object</InputHint>
<span class="plus">+</span>
<InputHint :inputKeys="['⇧']">Grow/Shrink Selection</InputHint>
<div class="divider"></div>
<InputHint :inputMouse="'LMBDrag'">Select Area</InputHint>
<span class="plus">+</span>
<InputHint :inputKeys="['⇧']">Grow/Shrink Selection</InputHint>
<div class="divider"></div>
<InputHint :inputKeys="['G']">Grab Selected</InputHint>
<InputHint :inputKeys="['R']">Rotate Selected</InputHint>
<InputHint :inputKeys="['S']">Scale Selected</InputHint>
<div class="divider"></div>
<InputHint :inputKeys="['↑', '→', '↓', '←']">Nudge Selected</InputHint>
<span class="plus">+</span>
<InputHint :inputKeys="['⇧']">Big Increment Nudge</InputHint>
<div class="divider"></div>
<InputHint :inputKeys="['Alt']" :inputMouse="'LMBDrag'">Move Duplicate</InputHint>
<InputHint :inputKeys="['Ctrl', 'D']">Duplicate</InputHint>
</div>
<div class="status-area footer-area">
<div>
<span>Graphite 0.0.1</span>
</div>
</div>
</template>
<style lang="scss">
.footer-area {
display: flex;
&.hint-area {
flex: 1 1 100%;
}
&.status-area div {
margin: 0 8px;
display: flex;
align-items: center;
white-space: nowrap;
}
}
.plus {
display: flex;
align-items: center;
font-weight: bold;
}
.divider {
width: 1px;
height: 16px;
margin: 4px 0;
background: #888;
}
.input-hint + .input-hint {
margin-left: 0;
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import InputHint from "./InputHint.vue";
export default defineComponent({
components: {
InputHint,
},
});
</script>

View File

@@ -0,0 +1,168 @@
<template>
<div class="input-hint">
<span class="input-key" v-for="inputKey in inputKeys" :key="inputKey" :class="keyCapWidth(inputKey)">
{{inputKey}}
</span>
<span class="input-mouse" v-if="inputMouse">
<svg width="16" height="16" viewBox="0 0 16 16" v-html="getMouseIconInnerSVG"></svg>
</span>
<span class="hint-text">
<slot></slot>
</span>
</div>
</template>
<style lang="scss">
.input-hint {
height: 100%;
margin: 0 8px;
display: flex;
align-items: center;
white-space: nowrap;
.input-key, .input-mouse {
margin-right: 4px;
}
.input-key {
font-family: "Inconsolata", monospace;
font-weight: bold;
text-align: center;
color: #111;
background: #ddd;
border: 1px;
box-sizing: border-box;
border-style: solid;
border-color: #888;
border-radius: 4px;
height: 16px;
line-height: 16px;
}
.input-key.width-16 {
width: 16px;
}
.input-key.width-24 {
width: 24px;
}
.input-key.width-32 {
width: 32px;
}
.input-key.width-40 {
width: 40px;
}
.input-key.width-48 {
width: 48px;
}
.input-mouse {
font-size: 0;
.bright {
fill: #ddd;
}
.dim {
fill: #888;
}
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
export enum MouseInputInteraction {
"None" = "None",
"LMB" = "LMB",
"RMB" = "RMB",
"MMB" = "MMB",
"ScrollUp" = "ScrollUp",
"ScrollDown" = "ScrollDown",
"Drag" = "Drag",
"LMBDrag" = "LMBDrag",
"RMBDrag" = "RMBDrag",
"MMBDrag" = "MMBDrag",
}
export default defineComponent({
props: {
inputKeys: { type: Array, default: () => [] },
inputMouse: { type: String },
},
methods: {
keyCapWidth(keyText: string) {
return `width-${keyText.length * 8 + 8}`;
},
},
computed: {
getMouseIconInnerSVG(): string {
switch (this.inputMouse) {
case MouseInputInteraction.None: return `
<path class="dim" d="M9,7c0,0.55-0.45,1-1,1l0,0C7.45,8,7,7.55,7,7V4.5c0-0.55,0.45-1,1-1l0,0c0.55,0,1,0.45,1,1V7z" />
<path class="dim" d="M10,2c1.1,0,2,0.9,2,2v6c0,2.21-1.79,4-4,4s-4-1.79-4-4V4c0-1.1,0.9-2,2-2H10 M10,1H6
C4.35,1,3,2.35,3,4v6c0,2.76,2.24,5,5,5s5-2.24,5-5V4C13,2.35,11.65,1,10,1L10,1z" />`;
case MouseInputInteraction.LMB: return `
<path class="bright" d="M8,1H6C4.35,1,3,2.35,3,4v4h5V1z" />
<path class="dim" d="M10,1H9v1h1c1.1,0,2,0.9,2,2v6c0,2.21-1.79,4-4,4s-4-1.79-4-4V9H3v1c0,2.76,2.24,5,5,5s5-2.24,5-5V4
C13,2.35,11.65,1,10,1z" />`;
case MouseInputInteraction.RMB: return `
<path class="dim" d="M8,1h2c1.65,0,3,1.35,3,3v4H8V1z" />
<path class="bright" d="M6,1h1v1H6C4.9,2,4,2.9,4,4v6c0,2.21,1.79,4,4,4s4-1.79,4-4V9h1v1c0,2.76-2.24,5-5,5s-5-2.24-5-5V4
C3,2.35,4.35,1,6,1z" />`;
case MouseInputInteraction.MMB: return `
<path class="bright" d="M9,7c0,0.55-0.45,1-1,1l0,0C7.45,8,7,7.55,7,7V4.5c0-0.55,0.45-1,1-1l0,0c0.55,0,1,0.45,1,1V7z" />
<path class="dim" d="M10,2c1.1,0,2,0.9,2,2v6c0,2.21-1.79,4-4,4s-4-1.79-4-4V4c0-1.1,0.9-2,2-2H10 M10,1H6
C4.35,1,3,2.35,3,4v6c0,2.76,2.24,5,5,5s5-2.24,5-5V4C13,2.35,11.65,1,10,1L10,1z" />`;
case MouseInputInteraction.ScrollUp: return `
<polygon class="bright" points="10.5,4 8,2 5.5,4 5.5,2 8,0 10.5,2" />
<polygon class="bright" points="10.5,8 8,6 5.5,8 5.5,6 8,4 10.5,6" />
<path class="dim" d="M11.5,1.42v1.28C11.8,3.06,12,3.5,12,4v6c0,2.21-1.79,4-4,4s-4-1.79-4-4V4c0-0.5,0.2-0.94,0.5-1.29
V1.42C3.61,1.94,3,2.9,3,4v6c0,2.76,2.24,5,5,5s5-2.24,5-5V4C13,2.9,12.39,1.94,11.5,1.42z" />`;
case MouseInputInteraction.ScrollDown: return `
<polygon class="bright" points="5.5,4 8,6 10.5,4 10.5,6 8,8 5.5,6" />
<polygon class="bright" points="5.5,0 8,2 10.5,0 10.5,2 8,4 5.5,2" />
<path class="dim" d="M11.5,1.42v1.28C11.8,3.06,12,3.5,12,4v6c0,2.21-1.79,4-4,4s-4-1.79-4-4V4c0-0.5,0.2-0.94,0.5-1.29
V1.42C3.61,1.94,3,2.9,3,4v6c0,2.76,2.24,5,5,5s5-2.24,5-5V4C13,2.9,12.39,1.94,11.5,1.42z" />`;
case MouseInputInteraction.Drag: return `
<path class="dim" d="M8,7c0,0.55-0.45,1-1,1l0,0C6.45,8,6,7.55,6,7V4.5c0-0.55,0.45-1,1-1l0,0c0.55,0,1,0.45,1,1V7z" />
<path class="bright" d="M11,16c-0.18,0-0.36-0.1-0.45-0.28c-0.12-0.25-0.02-0.55,0.22-0.67C10.87,15.01,13,13.88,13,11V6
c0-0.28,0.22-0.5,0.5-0.5S14,5.72,14,6v5c0,3.52-2.66,4.89-2.78,4.95C11.15,15.98,11.08,16,11,16z" />
<path class="bright" d="M14.5,15c-0.13,0-0.26-0.05-0.35-0.15c-0.19-0.19-0.2-0.51,0-0.7C14.17,14.12,15,13.2,15,11V8
c0-0.28,0.22-0.5,0.5-0.5S16,7.72,16,8v3c0,2.68-1.1,3.81-1.15,3.85C14.76,14.95,14.63,15,14.5,15z" />
<path class="dim" d="M9,2c1.1,0,2,0.9,2,2v6c0,2.21-1.79,4-4,4s-4-1.79-4-4V4c0-1.1,0.9-2,2-2H9 M9,1H5C3.35,1,2,2.35,2,4
v6c0,2.76,2.24,5,5,5s5-2.24,5-5V4C12,2.35,10.65,1,9,1L9,1z" />`;
case MouseInputInteraction.LMBDrag: return `
<path class="bright" d="M11,16c-0.18,0-0.36-0.1-0.45-0.28c-0.12-0.25-0.02-0.55,0.22-0.67C10.87,15.01,13,13.88,13,11V6
c0-0.28,0.22-0.5,0.5-0.5S14,5.72,14,6v5c0,3.52-2.66,4.89-2.78,4.95C11.15,15.98,11.08,16,11,16z" />
<path class="bright" d="M14.5,15c-0.13,0-0.26-0.05-0.35-0.15c-0.19-0.19-0.2-0.51,0-0.7C14.17,14.12,15,13.2,15,11V8
c0-0.28,0.22-0.5,0.5-0.5S16,7.72,16,8v3c0,2.68-1.1,3.81-1.15,3.85C14.76,14.95,14.63,15,14.5,15z" />
<path class="bright" d="M7,1H5C3.35,1,2,2.35,2,4v4h5V1z" />
<path class="dim" d="M9,1H8v1h1c1.1,0,2,0.9,2,2v6c0,2.21-1.79,4-4,4s-4-1.79-4-4V9H2v1c0,2.76,2.24,5,5,5s5-2.24,5-5V4
C12,2.35,10.65,1,9,1z" />`;
case MouseInputInteraction.RMBDrag: return `
<path class="bright" d="M11,16c-0.18,0-0.36-0.1-0.45-0.28c-0.12-0.25-0.02-0.55,0.22-0.67C10.87,15.01,13,13.88,13,11V6
c0-0.28,0.22-0.5,0.5-0.5S14,5.72,14,6v5c0,3.52-2.66,4.89-2.78,4.95C11.15,15.98,11.08,16,11,16z" />
<path class="bright" d="M14.5,15c-0.13,0-0.26-0.05-0.35-0.15c-0.19-0.19-0.2-0.51,0-0.7C14.17,14.12,15,13.2,15,11V8
c0-0.28,0.22-0.5,0.5-0.5S16,7.72,16,8v3c0,2.68-1.1,3.81-1.15,3.85C14.76,14.95,14.63,15,14.5,15z" />
<path class="bright" d="M7,1h2c1.65,0,3,1.35,3,3v4H7V1z" />
<path class="dim" d="M5,1h1v1H5C3.9,2,3,2.9,3,4v6c0,2.21,1.79,4,4,4s4-1.79,4-4V9h1v1c0,2.76-2.24,5-5,5s-5-2.24-5-5V4
C2,2.35,3.35,1,5,1z" />`;
case MouseInputInteraction.MMBDrag: return `
<path class="bright" d="M8,7c0,0.55-0.45,1-1,1l0,0C6.45,8,6,7.55,6,7V4.5c0-0.55,0.45-1,1-1l0,0c0.55,0,1,0.45,1,1V7z" />
<path class="bright" d="M11,16c-0.18,0-0.36-0.1-0.45-0.28c-0.12-0.25-0.02-0.55,0.22-0.67C10.87,15.01,13,13.88,13,11V6
c0-0.28,0.22-0.5,0.5-0.5S14,5.72,14,6v5c0,3.52-2.66,4.89-2.78,4.95C11.15,15.98,11.08,16,11,16z" />
<path class="bright" d="M14.5,15c-0.13,0-0.26-0.05-0.35-0.15c-0.19-0.19-0.2-0.51,0-0.7C14.17,14.12,15,13.2,15,11V8
c0-0.28,0.22-0.5,0.5-0.5S16,7.72,16,8v3c0,2.68-1.1,3.81-1.15,3.85C14.76,14.95,14.63,15,14.5,15z" />
<path class="dim" d="M9,2c1.1,0,2,0.9,2,2v6c0,2.21-1.79,4-4,4s-4-1.79-4-4V4c0-1.1,0.9-2,2-2H9 M9,1H5C3.35,1,2,2.35,2,4
v6c0,2.76,2.24,5,5,5s5-2.24,5-5V4C12,2.35,10.65,1,9,1L9,1z" />`;
default: return "";
}
},
},
});
</script>

View File

@@ -0,0 +1,59 @@
<template>
<div class="entry">
<svg width="16" height="16" viewBox="0 0 16 16">
<path d="M5.5,10.2c0.1,0.2,0,0.3-0.1,0.4c-0.2,0.1-0.3,0-0.4-0.1c0,0,0,0,0,0L2.7,6.7c-0.1-0.2,0-0.3,0.1-0.4c0.2-0.1,0.3,0,0.4,0.1
L5.5,10.2z M14.9,14.9L14.9,14.9C14.9,14.9,14.9,15,14.9,14.9C14.8,15,14.8,15,14.9,14.9L14.9,14.9c-0.5,0.2-1,0.4-1.5,0.5
c-0.5,0.1-1.1,0.2-1.6,0.2c-0.5,0.1-1.1,0.1-1.6,0c-0.5,0-1.1-0.1-1.6-0.1l-1.6-0.1c-1.7,0-3.9-0.1-4.4-0.1s-1.1-0.2-1.1-0.3
c0-0.1,0.3-0.2,0.6-0.2c0.5-0.1,1.1-0.2,1.7-0.3c0.6-0.1,2-0.2,4.1-0.2c0.8,0,1.8,0,1.8,0c0.6,0,1,0,1.9,0c0.7,0,1.1,0,1.2,0
c0.3,0,0.6,0.1,0.9,0.2l-2.6-1.9c-0.2,0.1-0.4,0.2-0.7,0.2H4.5c-0.5,0-0.9-0.2-1.1-0.6l-2.9-5c-0.2-0.4-0.2-0.9,0-1.3l2.9-5
C3.6,0.5,4,0.3,4.5,0.3h5.8c0.5,0,0.9,0.2,1.1,0.6l2.9,5l0,0l0,0c0,0.1,0.1,0.2,0.1,0.3c0,0,0,0.1,0,0.1c0,0.1,0,0.1,0,0.2
c0,0,0.7,7.2,0.7,7.8v0C15.2,14.6,15.1,14.8,14.9,14.9L14.9,14.9z M4.3,1.9L4.2,2l3.6,6.2c0.4-0.1,0.9-0.2,1.4-0.2l0.9-1.3l1.6-0.2
c0.2-0.4,0.5-0.8,0.8-1.1l-2.1-3.7c-0.1-0.2-0.3-0.3-0.5-0.3H4.8C4.6,1.6,4.4,1.7,4.3,1.9z M9.4,11.6l-2-1.4C7.4,10.1,7.3,10,7.3,10
l0,0L3.5,3.3l-1.7,3c-0.1,0.2-0.1,0.4,0,0.6l2.6,4.5c0.1,0.2,0.3,0.3,0.5,0.3L9.4,11.6z M13.5,11.3l-0.5-4.6c-0.3,0.3-0.5,0.7-0.7,1
l-1.6,0.2L9.8,9.2c-0.4,0-0.8,0-1.3,0.1l3.7,2.7C12.5,11.6,13,11.3,13.5,11.3L13.5,11.3z" />
</svg>
</div>
<div class="entry"><span>File</span></div>
<div class="entry"><span>Edit</span></div>
<div class="entry"><span>Document</span></div>
<div class="entry"><span>View</span></div>
<div class="entry"><span>Help</span></div>
</template>
<style lang="scss">
.entry {
display: flex;
align-items: center;
white-space: nowrap;
padding: 0 8px;
svg {
fill: #ddd;
}
&:hover {
background: #555;
svg {
fill: #fff;
}
span {
color: #fff;
}
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import { ApplicationPlatform } from "../MainWindow.vue";
export default defineComponent({
data() {
return {
ApplicationPlatform,
};
},
});
</script>

View File

@@ -0,0 +1,58 @@
<template>
<div class="header-third">
<WindowButtonsMac :maximized="maximized" v-if="platform === ApplicationPlatform.Mac" />
<FileMenu v-if="platform !== ApplicationPlatform.Mac" />
</div>
<div class="header-third">
<WindowTitle :title="'X-35B Over Death Valley.gdd* - Graphite'" />
</div>
<div class="header-third">
<WindowButtonsWindows :maximized="maximized" v-if="platform === ApplicationPlatform.Windows || platform === ApplicationPlatform.Linux" />
</div>
</template>
<style lang="scss">
.header-third {
display: flex;
flex: 1 1 100%;
&:nth-child(1) {
justify-content: flex-start;
}
&:nth-child(2) {
justify-content: center;
}
&:nth-child(3) {
justify-content: flex-end;
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import FileMenu from "./FileMenu.vue";
import WindowTitle from "./WindowTitle.vue";
import WindowButtonsWindows from "./WindowButtonsWindows.vue";
import WindowButtonsMac from "./WindowButtonsMac.vue";
import { ApplicationPlatform } from "../MainWindow.vue";
export default defineComponent({
components: {
FileMenu,
WindowTitle,
WindowButtonsWindows,
WindowButtonsMac,
},
props: {
platform: { type: String, required: true },
maximized: { type: Boolean, required: true },
},
data() {
return {
ApplicationPlatform,
};
},
});
</script>

View File

@@ -0,0 +1,45 @@
<template>
<div class="mac window-buttons">
<div class="close" title="Close"></div>
<div class="minimize" title="Minimize"></div>
<div class="zoom" title="Zoom"></div>
</div>
</template>
<style lang="scss">
.mac.window-buttons {
display: flex;
align-items: center;
div {
display: flex;
align-items: center;
margin-left: 8px;
width: 11px;
height: 11px;
border-radius: 50%;
&.close {
background: #ff5f57;
}
&.minimize {
background: #ffbd2f;
}
&.zoom {
background: #29c93f;
}
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
props: {
maximized: { type: Boolean, default: false },
},
});
</script>

View File

@@ -0,0 +1,56 @@
<template>
<div class="windows window-button minimize" title="Minimize">
<svg width="10" height="10" viewBox="0 0 10 10">
<rect y="4" width="10" height="1" />
</svg>
</div>
<div class="windows window-button maximize" title="Maximize" v-if="!maximized">
<svg width="10" height="10" viewBox="0 0 10 10">
<path d="M10,0v10H0V0H10z M9,1H1v8h8V1z" />
</svg>
</div>
<div class="windows window-button restore-down" title="Restore Down" v-if="maximized">
<svg width="10" height="10" viewBox="0 0 10 10">
<path d="M10,8H8v2H0V2h2V0h8V8z M7,3H1v6h6V3z M9,1H3v1h5v5h1V1z" />
</svg>
</div>
<div class="windows window-button close" title="Close">
<svg width="10" height="10" viewBox="0 0 10 10">
<polygon points="10,0.7 9.3,0 5,4.3 0.7,0 0,0.7 4.3,5 0,9.3 0.7,10 5,5.7 9.3,10 10,9.3 5.7,5" />
</svg>
</div>
</template>
<style lang="scss">
.windows.window-button {
display: flex;
align-items: center;
padding: 0 20px;
svg {
fill: #ddd;
}
&:hover {
background: #555;
svg {
fill: #fff;
}
}
&.close:hover {
background: #e81123;
}
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
props: {
maximized: { type: Boolean, default: false },
},
});
</script>

View File

@@ -0,0 +1,24 @@
<template>
<div class="window-title">
<span>{{title}}</span>
</div>
</template>
<style lang="scss">
.window-title {
display: flex;
align-items: center;
white-space: nowrap;
padding: 0 8px;
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
props: {
title: { type: String, required: true },
},
});
</script>