<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";

	// Graphite WASM editor
	export let editor: Editor;
	setContext("editor", editor);

	// State provider systems
	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);

	// Initialize managers, which are isolated systems that subscribe to backend messages to link them to browser API functionality (like JS events, IndexedDB, etc.)
	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>
