Improve tooltip docs with Markdown styling and refined math node explanations (#3488)

This commit is contained in:
Keavon Chambers
2025-12-20 01:05:15 -08:00
committed by GitHub
parent 2c21e1a90b
commit f1e8ebefc5
19 changed files with 276 additions and 185 deletions

View File

@@ -27,7 +27,7 @@
// State provider systems
let dialog = createDialogState(editor);
setContext("dialog", dialog);
let tooltip = createTooltipState();
let tooltip = createTooltipState(editor);
setContext("tooltip", tooltip);
let document = createDocumentState(editor);
setContext("document", document);

View File

@@ -1,9 +1,9 @@
<script lang="ts">
import { onDestroy, createEventDispatcher } from "svelte";
import { getContext, onDestroy, createEventDispatcher } from "svelte";
import type { HSV, RGB, FillChoice } from "@graphite/messages";
import type { MenuDirection } from "@graphite/messages";
import type { HSV, RGB, FillChoice, MenuDirection } from "@graphite/messages";
import { Color, contrastingOutlineFactor, Gradient } from "@graphite/messages";
import type { TooltipState } from "@graphite/state-providers/tooltip";
import { clamp } from "@graphite/utility-functions/math";
import FloatingMenu from "@graphite/components/layout/FloatingMenu.svelte";
@@ -40,6 +40,7 @@
];
const dispatch = createEventDispatcher<{ colorOrGradient: FillChoice; startHistoryTransaction: undefined }>();
const tooltip = getContext<TooltipState>("tooltip");
export let colorOrGradient: FillChoice;
export let allowNone = false;
@@ -424,12 +425,16 @@
"--opaque-color-contrasting": (newColor.opaque() || new Color(0, 0, 0, 1)).contrastingColor(),
}}
>
{@const hueDescription = "The shade along the spectrum of the rainbow."}
{@const saturationDescription = "The vividness from grayscale to full color."}
{@const valueDescription = "The brightness from black to full color."}
<LayoutCol class="pickers-and-gradient">
<LayoutRow class="pickers">
<LayoutCol
class="saturation-value-picker"
data-tooltip-label="Saturation and Value"
data-tooltip-description={disabled ? "Disabled (read-only)." : ""}
data-tooltip-description={`To move only along the saturation (X) or value (Y) axis, perform the shortcut shown.${disabled ? "\n\nDisabled (read-only)." : ""}`}
data-tooltip-shortcut={$tooltip.shiftClickShortcut?.shortcut ? JSON.stringify($tooltip.shiftClickShortcut.shortcut) : undefined}
on:pointerdown={onPointerDown}
data-saturation-value-picker
>
@@ -449,7 +454,7 @@
<LayoutCol
class="hue-picker"
data-tooltip-label="Hue"
data-tooltip-description={`The shade along the spectrum of the rainbow.${disabled ? "\n\nDisabled (read-only)." : ""}`}
data-tooltip-description={`${hueDescription}${disabled ? "\n\nDisabled (read-only)." : ""}`}
on:pointerdown={onPointerDown}
data-hue-picker
>
@@ -522,10 +527,8 @@
</LayoutRow>
<!-- <DropdownInput entries={[[{ label: "sRGB" }]]} selectedIndex={0} disabled={true} tooltipDescription="Color model, color space, and HDR (coming soon)." /> -->
<LayoutRow>
<TextLabel
tooltipLabel="Hex Color Code"
tooltipDescription="Color code in hexadecimal format. 6 digits if opaque, 8 with alpha.\nAccepts input of CSS color values including named colors.">Hex</TextLabel
>
{@const hexDescription = "Color code in hexadecimal format. 6 digits if opaque, 8 with alpha. Accepts input of CSS color values including named colors."}
<TextLabel tooltipLabel="Hex Color Code" tooltipDescription={hexDescription}>Hex</TextLabel>
<Separator type="Related" />
<LayoutRow>
<TextInput
@@ -537,7 +540,7 @@
}}
centered={true}
tooltipLabel="Hex Color Code"
tooltipDescription="Color code in hexadecimal format. 6 digits if opaque, 8 with alpha.\nAccepts input of CSS color values including named colors."
tooltipDescription={hexDescription}
bind:this={hexCodeInputWidget}
/>
</LayoutRow>
@@ -601,16 +604,17 @@
v: "Value Component",
}[channel]}
tooltipDescription={{
h: "The shade along the spectrum of the rainbow.",
s: "The vividness from grayscale to full color.",
v: "The brightness from black to full color.",
h: hueDescription,
s: saturationDescription,
v: valueDescription,
}[channel]}
/>
{/each}
</LayoutRow>
</LayoutRow>
<LayoutRow>
<TextLabel tooltipLabel="Alpha" tooltipDescription="The level of translucency, from transparent (0%) to opaque (100%).">Alpha</TextLabel>
{@const alphaDescription = "The level of translucency, from transparent (0%) to opaque (100%)."}
<TextLabel tooltipLabel="Alpha" tooltipDescription={alphaDescription}>Alpha</TextLabel>
<Separator type="Related" />
<NumberInput
value={!isNone ? alpha * 100 : undefined}
@@ -630,7 +634,7 @@
mode="Range"
displayDecimalPlaces={1}
tooltipLabel="Alpha"
tooltipDescription="The level of translucency, from transparent (0%) to opaque (100%)."
tooltipDescription={alphaDescription}
/>
</LayoutRow>
<LayoutRow class="leftover-space" />
@@ -670,7 +674,7 @@
data-pure-tile={name.toLowerCase()}
style:--pure-color={color}
style:--pure-color-gray={gray}
data-tooltip-label="Set to Red"
data-tooltip-label={`Set to ${name}`}
data-tooltip-description={disabled ? "Disabled (read-only)." : ""}
/>
{/each}

View File

@@ -15,8 +15,8 @@
let self: FloatingMenu | undefined;
$: label = filterTodo($tooltip.element?.getAttribute("data-tooltip-label")?.trim());
$: description = filterTodo($tooltip.element?.getAttribute("data-tooltip-description")?.trim());
$: label = parseMarkdown(filterTodo($tooltip.element?.getAttribute("data-tooltip-label")?.trim()));
$: description = parseMarkdown(filterTodo($tooltip.element?.getAttribute("data-tooltip-description")?.trim()));
$: shortcutJSON = $tooltip.element?.getAttribute("data-tooltip-shortcut")?.trim();
$: shortcut = ((shortcutJSON) => {
if (!shortcutJSON) return undefined;
@@ -32,6 +32,26 @@
if (text?.trim().toUpperCase() === "TODO" && !editor.handle.inDevelopmentMode()) return "";
return text;
}
function parseMarkdown(markdown: string | undefined): string | undefined {
if (!markdown) return undefined;
return (
markdown
// .split("\n")
// .map((line) => line.trim())
// .join("\n")
// .split("\n\n")
// .map((paragraph) => paragraph.replaceAll("\n", " "))
// .join("\n\n")
// Bold
.replace(/\*\*((?:(?!\*\*).)+)\*\*/g, "<strong>$1</strong>")
// Italic
.replace(/\*([^*]+)\*/g, "<em>$1</em>")
// Backticks
.replace(/`([^`]+)`/g, "<code>$1</code>")
);
}
</script>
{#if label || description}
@@ -40,7 +60,7 @@
{#if label || shortcut}
<LayoutRow class="tooltip-header">
{#if label}
<TextLabel class="tooltip-label">{label}</TextLabel>
<TextLabel class="tooltip-label">{@html label}</TextLabel>
{/if}
{#if shortcut}
<ShortcutLabel shortcut={{ shortcut }} />
@@ -48,7 +68,7 @@
</LayoutRow>
{/if}
{#if description}
<TextLabel class="tooltip-description">{description}</TextLabel>
<TextLabel class="tooltip-description">{@html description}</TextLabel>
{/if}
</FloatingMenu>
</div>

View File

@@ -9,10 +9,10 @@
UpdateLayersPanelControlBarLeftLayout,
UpdateLayersPanelControlBarRightLayout,
UpdateLayersPanelBottomBarLayout,
SendShortcutAltClick,
} from "@graphite/messages";
import type { ActionShortcut, DataBuffer, LayerPanelEntry, Layout } from "@graphite/messages";
import type { DataBuffer, LayerPanelEntry, Layout } from "@graphite/messages";
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
import type { TooltipState } from "@graphite/state-providers/tooltip";
import { operatingSystem } from "@graphite/utility-functions/platform";
import { extractPixelData } from "@graphite/utility-functions/rasterization";
@@ -49,6 +49,7 @@
const editor = getContext<Editor>("editor");
const nodeGraph = getContext<NodeGraphState>("nodeGraph");
const tooltip = getContext<TooltipState>("tooltip");
let list: LayoutCol | undefined;
@@ -73,13 +74,7 @@
let layersPanelControlBarRightLayout: Layout = [];
let layersPanelBottomBarLayout: Layout = [];
let altClickShortcut: ActionShortcut | undefined;
onMount(() => {
editor.subscriptions.subscribeJsMessage(SendShortcutAltClick, async (data) => {
altClickShortcut = data.shortcut;
});
editor.subscriptions.subscribeJsMessage(UpdateLayersPanelControlBarLeftLayout, (updateLayersPanelControlBarLeftLayout) => {
patchLayout(layersPanelControlBarLeftLayout, updateLayersPanelControlBarLeftLayout);
layersPanelControlBarLeftLayout = layersPanelControlBarLeftLayout;
@@ -628,7 +623,7 @@
? "Hide the layers nested within. (To affect all open descendants, perform the shortcut shown.)"
: "Show the layers nested within. (To affect all closed descendants, perform the shortcut shown.)") +
(listing.entry.ancestorOfSelected && !listing.entry.expanded ? "\n\nA selected layer is currently contained within.\n" : "")}
data-tooltip-shortcut={altClickShortcut?.shortcut ? JSON.stringify(altClickShortcut.shortcut) : undefined}
data-tooltip-shortcut={$tooltip.altClickShortcut?.shortcut ? JSON.stringify($tooltip.altClickShortcut.shortcut) : undefined}
on:click={(e) => handleExpandArrowClickWithModifiers(e, listing.entry.id)}
tabindex="0"
></button>
@@ -639,8 +634,9 @@
<IconLabel
icon="Clipped"
class="clipped-arrow"
tooltipDescription="Clipping mask is active. To release it, perform the shortcut on the layer border."
tooltipShortcut={altClickShortcut}
tooltipLabel="Layer Clipped"
tooltipDescription="Clipping mask is active. To release it, target the bottom border of the layer and perform the shortcut shown."
tooltipShortcut={$tooltip.altClickShortcut}
/>
{/if}
<div class="thumbnail">

View File

@@ -501,7 +501,7 @@
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
style:--layer-area-width={layerAreaWidth}
style:--node-chain-area-left-extension={layerChainWidth !== 0 ? layerChainWidth + 0.5 : 0}
data-tooltip-label={node.displayName === node.reference ? node.displayName : `${node.displayName} (${node.reference})`}
data-tooltip-label={node.displayName === node.reference || !node.reference ? node.displayName : `${node.displayName} (${node.reference})`}
data-tooltip-description={`
${(description || "").trim()}${editor.handle.inDevelopmentMode() ? `\n\nID: ${node.id}. Position: (${node.position.x}, ${node.position.y}).` : ""}
`.trim()}
@@ -651,7 +651,7 @@
style:--clip-path-id={`url(#${clipPathId})`}
style:--data-color={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()})`}
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
data-tooltip-label={node.displayName === node.reference ? node.displayName : `${node.displayName} (${node.reference})`}
data-tooltip-label={node.displayName === node.reference || !node.reference ? node.displayName : `${node.displayName} (${node.reference})`}
data-tooltip-description={`
${(description || "").trim()}${editor.handle.inDevelopmentMode() ? `\n\nID: ${node.id}. Position: (${node.position.x}, ${node.position.y}).` : ""}
`.trim()}

View File

@@ -72,7 +72,8 @@
font-style: italic;
}
&.monospace {
&.monospace,
code {
font-family: "Source Code Pro", monospace;
font-size: 12px;
}
@@ -94,5 +95,10 @@
a {
color: inherit;
}
code {
background: var(--color-3-darkgray);
padding: 0 2px;
}
}
</style>

View File

@@ -1,24 +1,15 @@
<script lang="ts">
import { getContext, onMount } from "svelte";
import { getContext } from "svelte";
import type { Editor } from "@graphite/editor";
import type { ActionShortcut } from "@graphite/messages";
import { SendShortcutF11 } from "@graphite/messages";
import type { FullscreenState } from "@graphite/state-providers/fullscreen";
import type { TooltipState } from "@graphite/state-providers/tooltip";
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
const fullscreen = getContext<FullscreenState>("fullscreen");
const editor = getContext<Editor>("editor");
let f11Shortcut: ActionShortcut | undefined = undefined;
onMount(() => {
editor.subscriptions.subscribeJsMessage(SendShortcutF11, async (data) => {
f11Shortcut = data.shortcut;
});
});
const tooltip = getContext<TooltipState>("tooltip");
async function handleClick() {
if ($fullscreen.windowFullscreen) fullscreen.exitFullscreen();
@@ -31,7 +22,7 @@
on:click={handleClick}
tooltipLabel={$fullscreen.windowFullscreen ? "Exit Fullscreen" : "Enter Fullscreen"}
tooltipDescription={$fullscreen.keyboardLockApiSupported ? "While fullscreen, keyboard shortcuts normally reserved by the browser become available." : ""}
tooltipShortcut={f11Shortcut}
tooltipShortcut={$tooltip.f11Shortcut}
>
<IconLabel icon={$fullscreen.windowFullscreen ? "FullscreenExit" : "FullscreenEnter"} />
</LayoutRow>