mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-24 13:08:12 +08:00
Improve font import; replace Inconsolata with Source Code Pro; show third-party licenses in editor dialog (#3079)
* Improve font import; replace Inconsolata with Source Code Pro; show third-party licenses in editor dialog * Code review
This commit is contained in:
@@ -352,4 +352,44 @@
|
||||
:not(.optional-input) > .checkbox-input input:focus-visible + label.checked {
|
||||
outline: 1px dashed var(--color-2-mildblack);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Sans Pro";
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
src: url("@graphite/../node_modules/source-sans/WOFF2/TTF/SourceSansPro-Regular.ttf.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Sans Pro";
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
src: url("@graphite/../node_modules/source-sans/WOFF2/TTF/SourceSansPro-It.ttf.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Sans Pro";
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
src: url("@graphite/../node_modules/source-sans/WOFF2/TTF/SourceSansPro-Bold.ttf.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Sans Pro";
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
src: url("@graphite/../node_modules/source-sans/WOFF2/TTF/SourceSansPro-BoldIt.ttf.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Code Pro";
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
src: url("@graphite/../node_modules/source-code-pro/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2") format("woff2");
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
.header-area,
|
||||
.footer-area {
|
||||
background: var(--color-1-nearblack);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.header-area,
|
||||
@@ -113,6 +114,8 @@
|
||||
|
||||
.content {
|
||||
margin: -4px 0;
|
||||
padding-right: calc(24px + 1px * var(--even-integer-subpixel-expansion-x));
|
||||
padding-bottom: calc(16px + 1px * var(--even-integer-subpixel-expansion-y));
|
||||
|
||||
&.center .row {
|
||||
justify-content: center;
|
||||
@@ -126,18 +129,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
.details.text-label {
|
||||
-webkit-user-select: text; // Required as of Safari 15.0 (Graphite's minimum version) through the latest release
|
||||
user-select: text;
|
||||
white-space: pre-wrap;
|
||||
max-width: 400px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.radio-input button {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.text-label.multiline {
|
||||
-webkit-user-select: text; // Still required by Safari as of 2025
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
// Used by the "Third-Party Software License Notices" dialog
|
||||
.details:has(.text-label.multiline.monospace) {
|
||||
max-height: 60vh;
|
||||
max-width: 80vw;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
// Used by the "Open Demo Artwork" dialog
|
||||
.image-label {
|
||||
border-radius: 2px;
|
||||
|
||||
@@ -137,20 +137,23 @@
|
||||
// This solves antialiasing issues when the content isn't cleanly divisible by 2 and gets translated by (-50%, -50%) causing all its content to be blurry.
|
||||
const floatingMenuContentDiv = floatingMenuContent?.div?.();
|
||||
if (type === "Dialog" && floatingMenuContentDiv) {
|
||||
// TODO: Also use https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver to detect any changes which may affect the size of the content.
|
||||
// TODO: The current method only notices when the dialog size increases but can't detect when it decreases.
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
let { width, height } = entry.contentRect;
|
||||
const existingWidth = Number(floatingMenuContentDiv.style.getPropertyValue("--even-integer-subpixel-expansion-x"));
|
||||
const existingHeight = Number(floatingMenuContentDiv.style.getPropertyValue("--even-integer-subpixel-expansion-y"));
|
||||
|
||||
width = Math.ceil(width);
|
||||
if (width % 2 === 1) width += 1;
|
||||
height = Math.ceil(height);
|
||||
if (height % 2 === 1) height += 1;
|
||||
let { width, height } = entry.contentRect;
|
||||
width -= existingWidth;
|
||||
height -= existingHeight;
|
||||
|
||||
let targetWidth = Math.ceil(width);
|
||||
if (targetWidth % 2 === 1) targetWidth += 1;
|
||||
let targetHeight = Math.ceil(height);
|
||||
if (targetHeight % 2 === 1) targetHeight += 1;
|
||||
|
||||
// We have to set the style properties directly because attempting to do it through a Svelte bound property results in `afterUpdate()` being triggered
|
||||
floatingMenuContentDiv.style.setProperty("min-width", width === 0 ? "unset" : `${width}px`);
|
||||
floatingMenuContentDiv.style.setProperty("min-height", height === 0 ? "unset" : `${height}px`);
|
||||
floatingMenuContentDiv.style.setProperty("--even-integer-subpixel-expansion-x", `${targetWidth - width}`);
|
||||
floatingMenuContentDiv.style.setProperty("--even-integer-subpixel-expansion-y", `${targetHeight - height}`);
|
||||
});
|
||||
});
|
||||
resizeObserver.observe(floatingMenuContentDiv);
|
||||
@@ -158,14 +161,6 @@
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
// Remove the size constraint after the content updates so the resize observer can measure the content and reapply a newly calculated one
|
||||
const floatingMenuContentDiv = floatingMenuContent?.div?.();
|
||||
if (type === "Dialog" && floatingMenuContentDiv) {
|
||||
// We have to set the style properties directly because attempting to do it through a Svelte bound property results in `afterUpdate()` being triggered
|
||||
floatingMenuContentDiv.style.setProperty("min-width", "unset");
|
||||
floatingMenuContentDiv.style.setProperty("min-height", "unset");
|
||||
}
|
||||
|
||||
// Gets the client bounds of the elements and apply relevant styles to them.
|
||||
// TODO: Use DOM attribute bindings more whilst not causing recursive updates. Turning measuring on and off both causes the component to change,
|
||||
// TODO: which causes the `afterUpdate()` Svelte event to fire extraneous times (hurting performance and sometimes causing an infinite loop).
|
||||
|
||||
@@ -770,7 +770,7 @@
|
||||
width: 100%;
|
||||
|
||||
&:disabled {
|
||||
-webkit-user-select: none; // Required as of Safari 15.0 (Graphite's minimum version) through the latest release
|
||||
-webkit-user-select: none; // Still required by Safari as of 2025
|
||||
user-select: none;
|
||||
// Workaround for `user-select: none` not working on <input> elements
|
||||
pointer-events: none;
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
export let disabled = false;
|
||||
export let bold = false;
|
||||
export let italic = false;
|
||||
export let monospace = false;
|
||||
export let centerAlign = false;
|
||||
export let tableAlign = false;
|
||||
export let minWidth = 0;
|
||||
export let minWidth = "";
|
||||
export let multiline = false;
|
||||
export let tooltip: string | undefined = undefined;
|
||||
export let forCheckbox: bigint | undefined = undefined;
|
||||
@@ -28,10 +29,11 @@
|
||||
class:disabled
|
||||
class:bold
|
||||
class:italic
|
||||
class:monospace
|
||||
class:multiline
|
||||
class:center-align={centerAlign}
|
||||
class:table-align={tableAlign}
|
||||
style:min-width={minWidth > 0 ? `${minWidth}px` : undefined}
|
||||
style:min-width={minWidth || undefined}
|
||||
style={`${styleName} ${extraStyles}`.trim() || undefined}
|
||||
title={tooltip}
|
||||
for={forCheckbox !== undefined ? `checkbox-input-${forCheckbox}` : undefined}
|
||||
@@ -58,6 +60,11 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&.monospace {
|
||||
font-family: "Source Code Pro", monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&.multiline {
|
||||
white-space: pre-wrap;
|
||||
margin: 4px 0;
|
||||
|
||||
@@ -183,7 +183,8 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-family: "Source Code Pro", monospace;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
height: 16px;
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
// This file is the browser's entry point for the JS bundle
|
||||
|
||||
// Fonts
|
||||
import "@fontsource/inconsolata";
|
||||
import "@fontsource/source-sans-pro/400-italic.css";
|
||||
import "@fontsource/source-sans-pro/400.css";
|
||||
import "@fontsource/source-sans-pro/700-italic.css";
|
||||
import "@fontsource/source-sans-pro/700.css";
|
||||
|
||||
// `reflect-metadata` allows for runtime reflection of types in JavaScript.
|
||||
// It is needed for class-transformer to work and is imported as a side effect.
|
||||
// The library replaces the Reflect API on the window to support more features.
|
||||
|
||||
@@ -946,6 +946,8 @@ export class TriggerAboutGraphiteLocalizedCommitDate extends JsMessage {
|
||||
readonly commitDate!: string;
|
||||
}
|
||||
|
||||
export class TriggerDisplayThirdPartyLicensesDialog extends JsMessage {}
|
||||
|
||||
// WIDGET PROPS
|
||||
|
||||
export abstract class WidgetProps {
|
||||
@@ -1370,13 +1372,15 @@ export class TextLabel extends WidgetProps {
|
||||
|
||||
italic!: boolean;
|
||||
|
||||
monospace!: boolean;
|
||||
|
||||
multiline!: boolean;
|
||||
|
||||
centerAlign!: boolean;
|
||||
|
||||
tableAlign!: boolean;
|
||||
|
||||
minWidth!: number;
|
||||
|
||||
multiline!: boolean;
|
||||
minWidth!: string;
|
||||
|
||||
@Transform(({ value }: { value: string }) => value || undefined)
|
||||
tooltip!: string | undefined;
|
||||
@@ -1692,6 +1696,7 @@ export const messageMakers: Record<string, MessageMaker> = {
|
||||
DisplayRemoveEditableTextbox,
|
||||
SendUIMetadata,
|
||||
TriggerAboutGraphiteLocalizedCommitDate,
|
||||
TriggerDisplayThirdPartyLicensesDialog,
|
||||
TriggerSaveDocument,
|
||||
TriggerSaveFile,
|
||||
TriggerExportImage,
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import { type Editor } from "@graphite/editor";
|
||||
import { defaultWidgetLayout, DisplayDialog, DisplayDialogDismiss, UpdateDialogButtons, UpdateDialogColumn1, UpdateDialogColumn2, patchWidgetLayout } from "@graphite/messages";
|
||||
import {
|
||||
defaultWidgetLayout,
|
||||
DisplayDialog,
|
||||
DisplayDialogDismiss,
|
||||
UpdateDialogButtons,
|
||||
UpdateDialogColumn1,
|
||||
UpdateDialogColumn2,
|
||||
patchWidgetLayout,
|
||||
TriggerDisplayThirdPartyLicensesDialog,
|
||||
} from "@graphite/messages";
|
||||
import { type IconName } from "@graphite/utility-functions/icons";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
@@ -78,6 +87,17 @@ export function createDialogState(editor: Editor) {
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(DisplayDialogDismiss, dismissDialog);
|
||||
|
||||
editor.subscriptions.subscribeJsMessage(TriggerDisplayThirdPartyLicensesDialog, async () => {
|
||||
const BACKUP_URL = "https://editor.graphite.rs/third-party-licenses.txt";
|
||||
let licenseText = `Content was not able to load. Please check your network connection and try again.\n\nOr visit ${BACKUP_URL} for the license notices.`;
|
||||
if (editor.handle.inDevelopmentMode()) licenseText = `Third-party licenses are not available in development builds.\n\nVisit ${BACKUP_URL} for the license notices.`;
|
||||
|
||||
const response = await fetch("/third-party-licenses.txt");
|
||||
if (response.ok && response.headers.get("Content-Type")?.includes("text/plain")) licenseText = await response.text();
|
||||
|
||||
editor.handle.requestLicensesThirdPartyDialogWithLicenseText(licenseText);
|
||||
});
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
dismissDialog,
|
||||
|
||||
Reference in New Issue
Block a user