|
<script lang="ts"> |
|
import { onMount, onDestroy, setContext } from "svelte"; |
|
|
|
import { type Editor } from "@graphite/editor"; |
|
import { createClipboardManager } from "@graphite/io-managers/clipboard"; |
|
import { createDragManager } from "@graphite/io-managers/drag"; |
|
import { createHyperlinkManager } from "@graphite/io-managers/hyperlinks"; |
|
import { createInputManager } from "@graphite/io-managers/input"; |
|
import { createLocalizationManager } from "@graphite/io-managers/localization"; |
|
import { createPanicManager } from "@graphite/io-managers/panic"; |
|
import { createPersistenceManager } from "@graphite/io-managers/persistence"; |
|
import { createDialogState } from "@graphite/state-providers/dialog"; |
|
import { createDocumentState } from "@graphite/state-providers/document"; |
|
import { createFontsState } from "@graphite/state-providers/fonts"; |
|
import { createFullscreenState } from "@graphite/state-providers/fullscreen"; |
|
import { createNodeGraphState } from "@graphite/state-providers/node-graph"; |
|
import { createPortfolioState } from "@graphite/state-providers/portfolio"; |
|
import { operatingSystem } from "@graphite/utility-functions/platform"; |
|
|
|
import MainWindow from "@graphite/components/window/MainWindow.svelte"; |
|
|
|
|
|
export let editor: Editor; |
|
setContext("editor", editor); |
|
|
|
|
|
let dialog = createDialogState(editor); |
|
setContext("dialog", dialog); |
|
let document = createDocumentState(editor); |
|
setContext("document", document); |
|
let fonts = createFontsState(editor); |
|
setContext("fonts", fonts); |
|
let fullscreen = createFullscreenState(editor); |
|
setContext("fullscreen", fullscreen); |
|
let nodeGraph = createNodeGraphState(editor); |
|
setContext("nodeGraph", nodeGraph); |
|
let portfolio = createPortfolioState(editor); |
|
setContext("portfolio", portfolio); |
|
|
|
|
|
createClipboardManager(editor); |
|
createHyperlinkManager(editor); |
|
createLocalizationManager(editor); |
|
createPanicManager(editor, dialog); |
|
createPersistenceManager(editor, portfolio); |
|
let dragManagerDestructor = createDragManager(); |
|
let inputManagerDestructor = createInputManager(editor, dialog, portfolio, document, fullscreen); |
|
|
|
onMount(() => { |
|
// Initialize certain setup tasks required by the editor backend to be ready for the user now that the frontend is ready |
|
editor.handle.initAfterFrontendReady(operatingSystem()); |
|
}); |
|
|
|
onDestroy(() => { |
|
// Call the destructor for each manager |
|
dragManagerDestructor(); |
|
inputManagerDestructor(); |
|
}); |
|
</script> |
|
|
|
<MainWindow /> |
|
|
|
<style lang="scss" global> |
|
// Disable the spinning loading indicator |
|
body::after { |
|
content: none !important; |
|
} |
|
|
|
:root { |
|
// Replace usage of `-rgb` variants with CSS color() function to calculate alpha when browsers support it |
|
// See https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color() and https://caniuse.com/css-color-function |
|
// Specifically, support for the relative syntax is needed: `color(from var(--color-0-black) srgb r g b / 0.5)` to convert black to 50% alpha |
|
--color-0-black: #000; |
|
--color-0-black-rgb: 0, 0, 0; |
|
--color-1-nearblack: #111; |
|
--color-1-nearblack-rgb: 17, 17, 17; |
|
--color-2-mildblack: #222; |
|
--color-2-mildblack-rgb: 34, 34, 34; |
|
--color-3-darkgray: #333; |
|
--color-3-darkgray-rgb: 51, 51, 51; |
|
--color-4-dimgray: #444; |
|
--color-4-dimgray-rgb: 68, 68, 68; |
|
--color-5-dullgray: #555; |
|
--color-5-dullgray-rgb: 85, 85, 85; |
|
--color-6-lowergray: #666; |
|
--color-6-lowergray-rgb: 102, 102, 102; |
|
--color-7-middlegray: #777; |
|
--color-7-middlegray-rgb: 109, 109, 109; |
|
--color-8-uppergray: #888; |
|
--color-8-uppergray-rgb: 136, 136, 136; |
|
--color-9-palegray: #999; |
|
--color-9-palegray-rgb: 153, 153, 153; |
|
--color-a-softgray: #aaa; |
|
--color-a-softgray-rgb: 170, 170, 170; |
|
--color-b-lightgray: #bbb; |
|
--color-b-lightgray-rgb: 187, 187, 187; |
|
--color-c-brightgray: #ccc; |
|
--color-c-brightgray-rgb: 204, 204, 204; |
|
--color-d-mildwhite: #ddd; |
|
--color-d-mildwhite-rgb: 221, 221, 221; |
|
--color-e-nearwhite: #eee; |
|
--color-e-nearwhite-rgb: 238, 238, 238; |
|
--color-f-white: #fff; |
|
--color-f-white-rgb: 255, 255, 255; |
|
--color-error-red: #d6536e; |
|
--color-error-red-rgb: 214, 83, 110; |
|
--color-warning-yellow: #d5aa43; |
|
--color-warning-yellow-rgb: 213, 170, 67; |
|
|
|
--color-data-general: #cfcfcf; |
|
--color-data-general-dim: #8a8a8a; |
|
--color-data-raster: #e4bb72; |
|
--color-data-raster-dim: #8b7752; |
|
--color-data-vectordata: #65bbe5; |
|
--color-data-vectordata-dim: #4b778c; |
|
--color-data-group: #66b195; |
|
--color-data-group-dim: #3d725e; |
|
--color-data-artboard: #fbf9eb; |
|
--color-data-artboard-dim: #b9b9a9; |
|
--color-data-number: #c9a699; |
|
--color-data-number-dim: #886b60; |
|
|
|
--color-none: white; |
|
--color-none-repeat: no-repeat; |
|
--color-none-position: center center; |
|
// 24px tall, 48px wide |
|
--color-none-size-24px: 60px 24px; |
|
// Red diagonal slash (24px tall) |
|
--color-none-image-24px: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 24"><line stroke="red" stroke-width="4px" x1="0" y1="27" x2="60" y2="-3" /></svg>\ |
|
'); |
|
// 32px tall, 64px wide |
|
--color-none-size-32px: 80px 32px; |
|
// Red diagonal slash (32px tall) |
|
--color-none-image-32px: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 32"><line stroke="red" stroke-width="4px" x1="0" y1="36" x2="80" y2="-4" /></svg>\ |
|
'); |
|
|
|
--color-transparent-checkered-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); |
|
--color-transparent-checkered-background-size: 16px 16px, 16px 16px, 16px 16px; |
|
--color-transparent-checkered-background-position: 0 0, 8px 8px, 8px 8px; |
|
--color-transparent-checkered-background-position-plus-one: 1px 1px, 9px 9px, 9px 9px; |
|
--color-transparent-checkered-background-size-mini: 8px 8px, 8px 8px, 8px 8px; |
|
--color-transparent-checkered-background-position-mini: 0 0, 4px 4px, 4px 4px; |
|
--color-transparent-checkered-background-repeat: repeat, repeat, repeat; |
|
|
|
--inheritance-stripes-background: repeating-linear-gradient( |
|
-45deg, |
|
transparent 0px, |
|
transparent calc((3px * sqrt(2) / 2) - 0.5px), |
|
var(--color-5-dullgray) calc((3px * sqrt(2) / 2) - 0.5px), |
|
var(--color-5-dullgray) calc((3px * sqrt(2) / 2) + 0.5px), |
|
transparent calc((3px * sqrt(2) / 2) + 0.5px), |
|
transparent calc(6px * sqrt(2) / 2) |
|
); |
|
--inheritance-dots-background-4-dimgray: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 4" width="4px" height="4px" fill="%23444"><rect width="1" height="1" /><rect x="2" y="2" width="1" height="1" /></svg>\ |
|
'); |
|
--inheritance-dots-background-6-lowergray: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 4" width="4px" height="4px" fill="%23666"><rect width="1" height="1" /><rect x="2" y="2" width="1" height="1" /></svg>\ |
|
'); |
|
|
|
// Array of 2x3 dots (fill: --color-e-nearwhite) |
|
--icon-drag-grip: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 24" fill="%23eee">\ |
|
<circle cx="0.5" cy="1.5" r="0.5" /><circle cx="3.5" cy="1.5" r="0.5" />\ |
|
<circle cx="0.5" cy="4.5" r="0.5" /><circle cx="3.5" cy="4.5" r="0.5" />\ |
|
<circle cx="0.5" cy="7.5" r="0.5" /><circle cx="3.5" cy="7.5" r="0.5" />\ |
|
</svg>\ |
|
'); |
|
// Array of 2x3 dots (fill: --color-f-white) |
|
--icon-drag-grip-hover: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 24" fill="%23fff">\ |
|
<circle cx="0.5" cy="1.5" r="0.5" /><circle cx="3.5" cy="1.5" r="0.5" />\ |
|
<circle cx="0.5" cy="4.5" r="0.5" /><circle cx="3.5" cy="4.5" r="0.5" />\ |
|
<circle cx="0.5" cy="7.5" r="0.5" /><circle cx="3.5" cy="7.5" r="0.5" />\ |
|
</svg>\ |
|
'); |
|
// Array of 2x3 dots (fill: --color-8-uppergray) |
|
--icon-drag-grip-disabled: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 24" fill="%23888">\ |
|
<circle cx="0.5" cy="1.5" r="0.5" /><circle cx="3.5" cy="1.5" r="0.5" />\ |
|
<circle cx="0.5" cy="4.5" r="0.5" /><circle cx="3.5" cy="4.5" r="0.5" />\ |
|
<circle cx="0.5" cy="7.5" r="0.5" /><circle cx="3.5" cy="7.5" r="0.5" />\ |
|
</svg>\ |
|
'); |
|
|
|
// Arrow triangle (fill: --color-e-nearwhite) |
|
--icon-expand-collapse-arrow: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8"><polygon fill="%23eee" points="3,0 1,0 5,4 1,8 3,8 7,4" /></svg>\ |
|
'); |
|
// Arrow triangle (fill: --color-f-white) |
|
--icon-expand-collapse-arrow-hover: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8"><polygon fill="%23fff" points="3,0 1,0 5,4 1,8 3,8 7,4" /></svg>\ |
|
'); |
|
// Arrow triangle (fill: --color-8-uppergray) |
|
--icon-expand-collapse-arrow-disabled: url('data:image/svg+xml;utf8,\ |
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8"><polygon fill="%23888" points="3,0 1,0 5,4 1,8 3,8 7,4" /></svg>\ |
|
'); |
|
} |
|
|
|
html, |
|
body { |
|
margin: 0; |
|
height: 100%; |
|
background: var(--color-2-mildblack); |
|
overscroll-behavior: none; |
|
-webkit-user-select: none; // Required as of Safari 15.0 (Graphite's minimum version) through the latest release |
|
user-select: none; |
|
} |
|
|
|
// The default value of `auto` from the CSS spec is a footgun with flexbox layouts: |
|
// https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size |
|
* { |
|
min-width: 0; |
|
min-height: 0; |
|
} |
|
|
|
html, |
|
body, |
|
input, |
|
textarea, |
|
button { |
|
font-family: "Source Sans Pro", Arial, sans-serif; |
|
font-weight: 400; |
|
font-size: 14px; |
|
line-height: 1; |
|
color: var(--color-e-nearwhite); |
|
} |
|
|
|
svg, |
|
img { |
|
display: block; |
|
} |
|
|
|
.layout-row, |
|
.layout-col { |
|
.scrollable-x, |
|
.scrollable-y { |
|
overflow: hidden; |
|
|
|
scrollbar-width: thin; |
|
// Not supported in Safari |
|
scrollbar-color: var(--color-5-dullgray) transparent; |
|
|
|
// Safari (more capable, removed from recent versions of Chromium, possibly still supported in Safari but not tested) |
|
&::-webkit-scrollbar { |
|
width: calc(2px + 6px + 2px); |
|
height: calc(2px + 6px + 2px); |
|
} |
|
|
|
&::-webkit-scrollbar-track { |
|
box-shadow: inset 0 0 0 1px var(--color-5-dullgray); |
|
border: 2px solid transparent; |
|
border-radius: 10px; |
|
} |
|
|
|
&:hover::-webkit-scrollbar-track { |
|
box-shadow: inset 0 0 0 1px var(--color-6-lowergray); |
|
} |
|
|
|
&::-webkit-scrollbar-thumb { |
|
background-clip: padding-box; |
|
background-color: var(--color-5-dullgray); |
|
border: 2px solid transparent; |
|
border-radius: 10px; |
|
margin: 2px; |
|
} |
|
|
|
&:hover::-webkit-scrollbar-thumb { |
|
background-color: var(--color-6-lowergray); |
|
} |
|
|
|
&::-webkit-scrollbar-corner { |
|
background: none; |
|
} |
|
} |
|
|
|
.scrollable-x.scrollable-y { |
|
overflow: auto; |
|
} |
|
|
|
.scrollable-x:not(.scrollable-y) { |
|
overflow: auto hidden; |
|
} |
|
|
|
.scrollable-y:not(.scrollable-x) { |
|
overflow: hidden auto; |
|
} |
|
} |
|
|
|
// List of all elements that should show an outline when focused by tabbing or by clicking the element |
|
.dropdown-input .dropdown-box, |
|
.font-input .dropdown-box { |
|
&:focus { |
|
outline: 1px dashed var(--color-e-nearwhite); |
|
outline-offset: -1px; |
|
} |
|
} |
|
|
|
// List of all elements that should show an outline when focused by tabbing, but not by clicking the element |
|
.icon-button, |
|
.text-button, |
|
.popover-button, |
|
.color-button > button, |
|
.color-picker .preset-color, |
|
.working-colors-input .swatch > button, |
|
.radio-input button, |
|
.menu-list, |
|
.menu-list-button .entry, |
|
.layer-tree .expand-arrow, |
|
.widget-section .header { |
|
&:focus-visible { |
|
outline: 1px dashed var(--color-e-nearwhite); |
|
outline-offset: -1px; |
|
} |
|
|
|
// Variant: dark outline over light colors |
|
&.preset-color.white, |
|
&.text-button.emphasized { |
|
&:focus-visible { |
|
outline: 1px dashed var(--color-2-mildblack); |
|
} |
|
} |
|
} |
|
|
|
// Checkbox needs to apply the focus outline to its sibling label |
|
.optional-input input:focus-visible + label, |
|
.checkbox-input input:focus-visible + label { |
|
outline: 1px dashed var(--color-e-nearwhite); |
|
outline-offset: -1px; |
|
} |
|
|
|
// Variant: dark outline over light colors (when the checkbox is checked) |
|
:not(.optional-input) > .checkbox-input input:focus-visible + label.checked { |
|
outline: 1px dashed var(--color-2-mildblack); |
|
} |
|
</style> |
|
|