Add demo artwork

This commit is contained in:
Keavon Chambers 2023-08-22 03:26:59 -07:00
parent 0e97a256b7
commit 0dcfafbf64
33 changed files with 2133 additions and 1050 deletions

View file

@ -84,6 +84,10 @@
height: auto;
}
.image-label {
border-radius: 2px;
}
.panic-buttons-row {
height: 32px;
align-items: center;

View file

@ -24,6 +24,7 @@
import TextAreaInput from "@graphite/components/widgets/inputs/TextAreaInput.svelte";
import TextInput from "@graphite/components/widgets/inputs/TextInput.svelte";
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
import ImageLabel from "@graphite/components/widgets/labels/ImageLabel.svelte";
import Separator from "@graphite/components/widgets/labels/Separator.svelte";
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
import { getContext } from "svelte";
@ -120,6 +121,10 @@
{#if iconLabel}
<IconLabel {...exclude(iconLabel)} />
{/if}
{@const imageLabel = narrowWidgetProps(component.props, "ImageLabel")}
{#if imageLabel}
<ImageLabel {...exclude(imageLabel)} />
{/if}
{@const layerReferenceInput = narrowWidgetProps(component.props, "LayerReferenceInput")}
{#if layerReferenceInput}
<LayerReferenceInput {...exclude(layerReferenceInput)} on:value={({ detail }) => updateLayout(index, detail)} />

View file

@ -0,0 +1,29 @@
<script lang="ts">
import { IMAGE_BASE64_STRINGS } from "@graphite/utility-functions/images";
let className = "";
export { className as class };
export let classes: Record<string, boolean> = {};
export let image: string;
export let width: string | undefined;
export let height: string | undefined;
export let tooltip: string | undefined = undefined;
$: extraClasses = Object.entries(classes)
.flatMap((classAndState) => (classAndState[1] ? [classAndState[0]] : []))
.join(" ");
</script>
<img src={IMAGE_BASE64_STRINGS[image]} style:width style:height class={`image-label ${className} ${extraClasses}`.trim()} title={tooltip} alt="" />
<style lang="scss" global>
.image-label {
width: auto;
height: auto;
+ .image-label {
margin-left: 8px;
}
}
</style>

View file

@ -40,14 +40,6 @@
let tabElements: (LayoutRow | undefined)[] = [];
function newDocument() {
editor.instance.newDocumentDialog();
}
function openDocument() {
editor.instance.documentOpen();
}
function platformModifiers(reservedKey: boolean): LayoutKeysGroup {
// TODO: Remove this by properly feeding these keys from a layout provided by the backend
@ -128,7 +120,7 @@
<table>
<tr>
<td>
<TextButton label="New Document" icon="File" action={() => newDocument()} />
<TextButton label="New Document" icon="File" action={() => editor.instance.newDocumentDialog()} />
</td>
<td>
<UserInputLabel keysWithLabelsGroups={[[...platformModifiers(true), { key: "KeyN", label: "N" }]]} />
@ -136,12 +128,17 @@
</tr>
<tr>
<td>
<TextButton label="Open Document" icon="Folder" action={() => openDocument()} />
<TextButton label="Open Document" icon="Folder" action={() => editor.instance.openDocument()} />
</td>
<td>
<UserInputLabel keysWithLabelsGroups={[[...platformModifiers(false), { key: "KeyO", label: "O" }]]} />
</td>
</tr>
<tr>
<td colspan="2">
<TextButton label="Open Demo Artwork" icon="Image" action={() => editor.instance.demoArtworkDialog()} />
</td>
</tr>
</table>
</LayoutRow>
</LayoutCol>

View file

@ -5,3 +5,13 @@ declare module "*.svg" {
const content: string;
export default content;
}
declare module "*.png" {
const content: string;
export default content;
}
declare module "*.jpg" {
const content: string;
export default content;
}

View file

@ -8,10 +8,10 @@ import { type Editor } from "@graphite/wasm-communication/editor";
import {
type FrontendDocumentDetails,
TriggerCopyToClipboardBlobUrl,
TriggerFetchAndOpenDocument,
TriggerDownloadBlobUrl,
TriggerDownloadRaster,
TriggerDownloadTextFile,
TriggerImaginateCheckServerStatus,
TriggerImport,
TriggerOpenDocument,
TriggerRasterizeRegionBelowLayer,
@ -45,6 +45,19 @@ export function createPortfolioState(editor: Editor) {
return state;
})
});
editor.subscriptions.subscribeJsMessage(TriggerFetchAndOpenDocument, async (triggerFetchAndOpenDocument) => {
try {
const url = new URL(triggerFetchAndOpenDocument.url);
const data = await fetch(url);
const filename = url.pathname.split("/").pop() || "Untitled";
const content = await data.text();
editor.instance.openDocumentFile(filename, content);
} catch {
editor.instance.errorDialog("Failed to open document", "The file could not be reached over the internet. You may be offline, or it may be missing.");
}
});
editor.subscriptions.subscribeJsMessage(TriggerOpenDocument, async () => {
const extension = editor.instance.fileSaveSuffix();
const data = await upload(extension, "text");

View file

@ -113,7 +113,7 @@ import NodeBlur from "@graphite-frontend/assets/icon-16px-solid/node-blur.svg";
import NodeBrushwork from "@graphite-frontend/assets/icon-16px-solid/node-brushwork.svg";
import NodeColorCorrection from "@graphite-frontend/assets/icon-16px-solid/node-color-correction.svg";
import NodeGradient from "@graphite-frontend/assets/icon-16px-solid/node-gradient.svg";
import NodeImage from "@graphite-frontend/assets/icon-16px-solid/node-image.svg";
import Image from "@graphite-frontend/assets/icon-16px-solid/image.svg";
import NodeImaginate from "@graphite-frontend/assets/icon-16px-solid/node-imaginate.svg";
import NodeMagicWand from "@graphite-frontend/assets/icon-16px-solid/node-magic-wand.svg";
import NodeMask from "@graphite-frontend/assets/icon-16px-solid/node-mask.svg";
@ -176,7 +176,7 @@ const SOLID_16PX = {
NodeBrushwork: { svg: NodeBrushwork, size: 16 },
NodeColorCorrection: { svg: NodeColorCorrection, size: 16 },
NodeGradient: { svg: NodeGradient, size: 16 },
NodeImage: { svg: NodeImage, size: 16 },
Image: { svg: Image, size: 16 },
NodeImaginate: { svg: NodeImaginate, size: 16 },
NodeMagicWand: { svg: NodeMagicWand, size: 16 },
NodeMask: { svg: NodeMask, size: 16 },

View file

@ -0,0 +1,23 @@
/* eslint-disable import/first */
// Demo artwork
import ThumbnailJustAPottedCactus from "@graphite-frontend/assets/images/demo-artwork/thumbnail-just-a-potted-cactus.png";
import ThumbnailValleyOfSpires from "@graphite-frontend/assets/images/demo-artwork/thumbnail-valley-of-spires.png";
const DEMO_ARTWORK = {
ThumbnailJustAPottedCactus,
ThumbnailValleyOfSpires,
} as const;
// All images
const IMAGE_LIST = {
...DEMO_ARTWORK,
} as const;
// Exported images and types
export const IMAGES: ImageDefinitionType<typeof IMAGE_LIST> = IMAGE_LIST;
export const IMAGE_BASE64_STRINGS = Object.fromEntries(Object.entries(IMAGES).map(([name, data]) => [name, data]));
// See `icons.ts` for explanation about how this works
type EvaluateType<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
type ImageDefinitionType<T extends Record<string, string>> = EvaluateType<{ [key in keyof T]: string }>;

View file

@ -89,6 +89,21 @@ export function createEditor() {
// Subscriptions: Allows subscribing to messages in JS that are sent from the WASM backend
const subscriptions: SubscriptionRouter = createSubscriptionRouter();
// Check if the URL hash fragment has any demo artwork to be loaded
(async () => {
const demoArtwork = window.location.hash.trim().match(/#demo\/(.*)/)?.[1];
if (!demoArtwork) return;
try {
const url = new URL(`https://raw.githubusercontent.com/GraphiteEditor/Graphite/master/demo-artwork/${demoArtwork}.graphite`);
const data = await fetch(url);
const filename = url.pathname.split("/").pop() || "Untitled";
const content = await data.text();
instance.openDocumentFile(filename, content);
} catch {}
})();
return {
raw,
instance,

View file

@ -513,6 +513,10 @@ export class TriggerLoadAutoSaveDocuments extends JsMessage { }
export class TriggerLoadPreferences extends JsMessage { }
export class TriggerFetchAndOpenDocument extends JsMessage {
readonly url!: string;
}
export class TriggerOpenDocument extends JsMessage { }
export class TriggerImport extends JsMessage { }
@ -874,6 +878,19 @@ export class IconLabel extends WidgetProps {
tooltip!: string | undefined;
}
export class ImageLabel extends WidgetProps {
image!: IconName;
@Transform(({ value }: { value: string }) => value || undefined)
width!: string | undefined;
@Transform(({ value }: { value: string }) => value || undefined)
height!: string | undefined;
@Transform(({ value }: { value: string }) => value || undefined)
tooltip!: string | undefined;
}
export class LayerReferenceInput extends WidgetProps {
@Transform(({ value }: { value: BigUint64Array | undefined }) => (value ? String(value) : undefined))
value!: string | undefined;
@ -1120,6 +1137,7 @@ const widgetSubTypes = [
{ value: FontInput, name: "FontInput" },
{ value: IconButton, name: "IconButton" },
{ value: IconLabel, name: "IconLabel" },
{ value: ImageLabel, name: "ImageLabel" },
{ value: LayerReferenceInput, name: "LayerReferenceInput" },
{ value: NumberInput, name: "NumberInput" },
{ value: OptionalInput, name: "OptionalInput" },
@ -1367,6 +1385,7 @@ export const messageMakers: Record<string, MessageMaker> = {
DisplayRemoveEditableTextbox,
TriggerAboutGraphiteLocalizedCommitDate,
TriggerCopyToClipboardBlobUrl,
TriggerFetchAndOpenDocument,
TriggerDownloadBlobUrl,
TriggerDownloadRaster,
TriggerDownloadTextFile,