mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 19:08:13 +08:00
Restyle and refactor shortcut labels to send hints bar and welcome screen layouts from Rust (#3447)
* Restyle UserInputLabel and refactor its usages to have all input its data sent from Rust * Replace the welcome screen quick buttons with ones sent by backend * Add the ShortcutLabel widget to the backend * Replace hints bar with a backend-controlled layout; show mouse icons in place of mouse labels
This commit is contained in:
@@ -3,8 +3,10 @@
|
||||
import Document from "@graphite/components/panels/Document.svelte";
|
||||
import Layers from "@graphite/components/panels/Layers.svelte";
|
||||
import Properties from "@graphite/components/panels/Properties.svelte";
|
||||
import Welcome from "@graphite/components/panels/Welcome.svelte";
|
||||
|
||||
const PANEL_COMPONENTS = {
|
||||
Welcome,
|
||||
Document,
|
||||
Layers,
|
||||
Properties,
|
||||
@@ -17,23 +19,16 @@
|
||||
import { getContext, tick } from "svelte";
|
||||
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import { type LayoutKeysGroup, type Key } from "@graphite/messages";
|
||||
import type { AppWindowState } from "@graphite/state-providers/app-window";
|
||||
import { operatingSystem, isEventSupported } from "@graphite/utility-functions/platform";
|
||||
import { extractPixelData } from "@graphite/utility-functions/rasterization";
|
||||
import { isEventSupported } from "@graphite/utility-functions/platform";
|
||||
|
||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
|
||||
import TextButton from "@graphite/components/widgets/buttons/TextButton.svelte";
|
||||
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
|
||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||
import UserInputLabel from "@graphite/components/widgets/labels/UserInputLabel.svelte";
|
||||
|
||||
const BUTTON_LEFT = 0;
|
||||
const BUTTON_MIDDLE = 1;
|
||||
|
||||
const appWindow = getContext<AppWindowState>("appWindow");
|
||||
const editor = getContext<Editor>("editor");
|
||||
|
||||
export let tabMinWidths = false;
|
||||
@@ -54,52 +49,6 @@
|
||||
|
||||
let tabElements: (LayoutRow | undefined)[] = [];
|
||||
|
||||
function platformModifiedAccelKey(browserReservedKey: boolean): LayoutKeysGroup {
|
||||
// TODO: Remove this by properly feeding these keys from a layout provided by the backend
|
||||
|
||||
const ALT: Key = { key: "Alt", label: "Alt" };
|
||||
const COMMAND: Key = { key: "Command", label: "Command" };
|
||||
const CONTROL: Key = { key: "Control", label: "Ctrl" };
|
||||
|
||||
// Only consider the browser reserved key on web platforms
|
||||
const reservedKey = $appWindow.platform === "Web" ? browserReservedKey : false;
|
||||
|
||||
// Return either Command (Mac) or Control (Windows/Linux), with Alt added if the browser reserves the shortcut
|
||||
if (operatingSystem() === "Mac") return reservedKey ? [ALT, COMMAND] : [COMMAND];
|
||||
return reservedKey ? [CONTROL, ALT] : [CONTROL];
|
||||
}
|
||||
|
||||
function dropFile(e: DragEvent) {
|
||||
if (!e.dataTransfer) return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
Array.from(e.dataTransfer.items).forEach(async (item) => {
|
||||
const file = item.getAsFile();
|
||||
if (!file) return;
|
||||
|
||||
if (file.type.includes("svg")) {
|
||||
const svgData = await file.text();
|
||||
editor.handle.pasteSvg(file.name, svgData);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.type.startsWith("image")) {
|
||||
const imageData = await extractPixelData(file);
|
||||
editor.handle.pasteImage(file.name, new Uint8Array(imageData.data), imageData.width, imageData.height);
|
||||
return;
|
||||
}
|
||||
|
||||
const graphiteFileSuffix = "." + editor.handle.fileExtension();
|
||||
if (file.name.endsWith(graphiteFileSuffix)) {
|
||||
const content = await file.text();
|
||||
const documentName = file.name.slice(0, -graphiteFileSuffix.length);
|
||||
editor.handle.openDocumentFile(documentName, content);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onEmptySpaceAction(e: MouseEvent) {
|
||||
if (e.target !== e.currentTarget) return;
|
||||
if (e.button === BUTTON_MIDDLE || (e.button === BUTTON_LEFT && e.detail === 2)) emptySpaceAction?.();
|
||||
@@ -162,66 +111,10 @@
|
||||
</LayoutRow>
|
||||
{/each}
|
||||
</LayoutRow>
|
||||
<!-- <PopoverButton style="VerticalEllipsis">
|
||||
<TextLabel bold={true}>Panel Options</TextLabel>
|
||||
<TextLabel multiline={true}>Coming soon</TextLabel>
|
||||
</PopoverButton> -->
|
||||
</LayoutRow>
|
||||
<LayoutCol class="panel-body">
|
||||
{#if panelType}
|
||||
<svelte:component this={PANEL_COMPONENTS[panelType]} />
|
||||
{:else}
|
||||
<LayoutCol class="empty-panel" on:dragover={(e) => e.preventDefault()} on:drop={dropFile}>
|
||||
<LayoutCol class="top-spacer"></LayoutCol>
|
||||
<LayoutCol class="content-container">
|
||||
<LayoutCol class="content">
|
||||
<LayoutRow class="logotype">
|
||||
<IconLabel icon="GraphiteLogotypeSolid" />
|
||||
</LayoutRow>
|
||||
<LayoutRow class="actions">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<TextButton label="New Document" icon="File" flush={true} action={() => editor.handle.newDocumentDialog()} />
|
||||
</td>
|
||||
<td>
|
||||
<UserInputLabel keysWithLabelsGroups={[[...platformModifiedAccelKey(true), { key: "KeyN", label: "N" }]]} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<TextButton label="Open Document" icon="Folder" flush={true} action={() => editor.handle.openDocument()} />
|
||||
</td>
|
||||
<td>
|
||||
<UserInputLabel keysWithLabelsGroups={[[...platformModifiedAccelKey(false), { key: "KeyO", label: "O" }]]} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<TextButton label="Open Demo Artwork" icon="Image" flush={true} action={() => editor.handle.demoArtworkDialog()} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<TextButton label="Support the Development Fund" icon="Heart" flush={true} action={() => editor.handle.visitUrl("https://graphite.rs/donate/")} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</LayoutRow>
|
||||
</LayoutCol>
|
||||
</LayoutCol>
|
||||
<LayoutCol class="bottom-message">
|
||||
{#if new Date().getFullYear() === 2025}
|
||||
<TextLabel italic={true} disabled={true}>
|
||||
September 2025 release — <a href="https://youtube.com/watch?v=Vl5BA4g3QXM" target="_blank">What's new? (video)</a>
|
||||
— Note: some older documents may render differently and require manual fixes.
|
||||
<a href="https://ec6796b4.graphite-editor.pages.dev/" target="_blank">Need the old version?</a>
|
||||
</TextLabel>
|
||||
{/if}
|
||||
</LayoutCol>
|
||||
</LayoutCol>
|
||||
{/if}
|
||||
</LayoutCol>
|
||||
</LayoutCol>
|
||||
@@ -323,7 +216,7 @@
|
||||
left: -1px;
|
||||
width: 1px;
|
||||
height: 16px;
|
||||
background: var(--color-4-dimgray);
|
||||
background: var(--color-5-dullgray);
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
@@ -335,15 +228,11 @@
|
||||
right: -1px;
|
||||
width: 1px;
|
||||
height: 16px;
|
||||
background: var(--color-4-dimgray);
|
||||
background: var(--color-5-dullgray);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .popover-button {
|
||||
// margin: 2px 4px;
|
||||
// }
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
@@ -354,66 +243,11 @@
|
||||
> div {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.empty-panel {
|
||||
background: var(--color-2-mildblack);
|
||||
margin: 4px;
|
||||
border-radius: 2px;
|
||||
justify-content: space-between;
|
||||
|
||||
.content-container {
|
||||
flex: 0 0 auto;
|
||||
justify-content: center;
|
||||
|
||||
.content {
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
|
||||
.logotype {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 40px;
|
||||
|
||||
svg {
|
||||
width: auto;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-bottom: 8px;
|
||||
|
||||
table {
|
||||
border-spacing: 8px;
|
||||
margin: -8px;
|
||||
|
||||
td {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-spacer {
|
||||
flex: 0 1 48px;
|
||||
}
|
||||
|
||||
.bottom-message {
|
||||
flex: 0 0 48px;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
|
||||
.text-label {
|
||||
white-space: wrap;
|
||||
margin: 0 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Needed for the viewport hole punch on desktop
|
||||
.viewport-hole-punch &.document-panel,
|
||||
.viewport-hole-punch &.document-panel .panel-body:not(:has(.empty-panel)) {
|
||||
.viewport-hole-punch &.document-panel .panel-body:not(:has(.welcome-panel)) {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
<LayoutRow class="workspace-grid-subdivision" styles={{ "flex-grow": panelSizes["document"] }} data-subdivision-name="document">
|
||||
<Panel
|
||||
class="document-panel"
|
||||
panelType={$portfolio.documents.length > 0 ? "Document" : undefined}
|
||||
panelType={$portfolio.documents.length > 0 ? "Document" : "Welcome"}
|
||||
tabCloseButtons={true}
|
||||
tabMinWidths={true}
|
||||
tabLabels={documentTabLabels}
|
||||
|
||||
Reference in New Issue
Block a user