Release ForgeFlow 0.8.4 interactive illustrations
This commit is contained in:
+36
-2
@@ -699,6 +699,19 @@ function queueActionFor(repository) {
|
||||
return mapping[action.kind] || mapping.clean;
|
||||
}
|
||||
|
||||
function projectIllustration(kind = "flow") {
|
||||
return `<div class="project-illustration ${attr(kind)}" data-project-illustration aria-hidden="true">
|
||||
<div class="illustration-glow"></div><svg viewBox="0 0 260 150" role="presentation">
|
||||
<path class="orbit orbit-a" d="M32 92 C72 20 190 18 230 82"/><path class="orbit orbit-b" d="M42 116 C98 150 190 136 222 60"/>
|
||||
<g class="illustration-core"><rect x="83" y="39" width="94" height="74" rx="17"/><path d="M103 66h54M103 79h36M103 92h45"/><circle cx="160" cy="92" r="5"/></g>
|
||||
<g class="illustration-node node-a"><circle cx="37" cy="92" r="12"/><path d="m32 92 4 4 7-9"/></g>
|
||||
<g class="illustration-node node-b"><circle cx="226" cy="82" r="12"/><path d="M221 82h10M226 77v10"/></g>
|
||||
<g class="illustration-node node-c"><circle cx="74" cy="31" r="8"/></g>
|
||||
<circle class="signal signal-a" cx="0" cy="0" r="4"/><circle class="signal signal-b" cx="0" cy="0" r="3"/>
|
||||
</svg><span class="illustration-label">${kind === "deploy" ? "Live release topology" : kind === "repo" ? "Project signal" : "Release flow"}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderOverview() {
|
||||
const changed = ui.repositories.filter(
|
||||
(repository) => repository.localStatus?.counts.changed,
|
||||
@@ -720,7 +733,7 @@ function renderOverview() {
|
||||
(operation) => !isTerminalOperation(operation.status),
|
||||
);
|
||||
return `<div class="page">
|
||||
<div class="page-header"><div><div class="eyebrow">Coding flow</div><h1>Release overview</h1><p>One decision surface for local work, Gitea synchronization and the exact version running on your server.</p></div><button class="button" data-action="refresh">${icon("refresh")}Refresh all</button></div>
|
||||
<div class="page-header visual-page-header"><div><div class="eyebrow">Coding flow</div><h1>Release overview</h1><p>One decision surface for local work, Gitea synchronization and the exact version running on your server.</p></div>${projectIllustration("flow")}<button class="button" data-action="refresh">${icon("refresh")}Refresh all</button></div>
|
||||
${ui.refreshError ? `<div class="notice danger">${icon("error")} ${escapeHtml(ui.refreshError)}</div>` : ""}
|
||||
<div class="summary-grid">
|
||||
${renderSummaryCard("Local work", changed, changed === 1 ? "repository has changes" : "repositories have changes", "file", changed ? "warning" : "success")}
|
||||
@@ -951,7 +964,7 @@ function renderRepositoryWorkspace(repository) {
|
||||
settings: renderRepositorySettings,
|
||||
}[ui.repositoryTab] || renderChanges
|
||||
)(repository);
|
||||
return `<div class="repo-workspace"><header class="repo-header"><div class="repo-heading"><h1><button class="favorite-button ${repository.favorite ? "active" : ""}" data-action="toggle-favorite" title="Toggle favorite">${icon("star")}</button>${escapeHtml(repository.fullName)}</h1><p>${escapeHtml(repository.localPath || "No local working tree linked")}</p></div><div class="repo-header-actions"><button class="button" data-action="fetch" ${!repository.localPath ? "disabled" : ""}>${icon("refresh")}Fetch</button><button class="button" data-action="open-path" ${!repository.localPath ? "disabled" : ""}>${icon("folder")}Folder</button><button class="button" data-action="open-gitea" ${!repository.htmlUrl ? "disabled" : ""}>${icon("external")}Gitea</button></div></header>
|
||||
return `<div class="repo-workspace"><header class="repo-header illustrated-repo-header"><div class="repo-heading"><h1><button class="favorite-button ${repository.favorite ? "active" : ""}" data-action="toggle-favorite" title="Toggle favorite">${icon("star")}</button>${escapeHtml(repository.fullName)}</h1><p>${escapeHtml(repository.localPath || "No local working tree linked")}</p></div>${projectIllustration("repo")}<div class="repo-header-actions"><button class="button" data-action="fetch" ${!repository.localPath ? "disabled" : ""}>${icon("refresh")}Fetch</button><button class="button" data-action="open-path" ${!repository.localPath ? "disabled" : ""}>${icon("folder")}Folder</button><button class="button" data-action="open-gitea" ${!repository.htmlUrl ? "disabled" : ""}>${icon("external")}Gitea</button></div></header>
|
||||
${repository.localPath ? `<div class="repo-quick-actions"><button class="button" data-action="open-editor">${icon("external")}Open in editor</button><button class="button" data-action="open-terminal">${icon("terminal")}Open terminal</button><button class="button" data-action="check-branch-protection">${icon("shield")}Check branch protection</button><button class="button primary" data-action="open-pull-request">${icon("git")}Create pull request</button>${ui.branchProtection ? `<span class="status-pill ${ui.branchProtection.protected ? "warning" : "success"}">${ui.branchProtection.protected ? `Protected · ${ui.branchProtection.requiredApprovals || 0} approval(s)` : "Direct pushes allowed"}</span>` : ""}</div>` : ""}
|
||||
<div class="release-rail">${releaseNode("Local", status?.shortHead || "Not linked", status ? `${status.counts.changed} changes · ${status.branch.head}` : "No working tree", localTone)}${releaseNode("Gitea", status?.shortHead || "Unknown", status?.branch.upstream ? `${status.branch.ahead} ahead · ${status.branch.behind} behind` : "Branch not published", remoteTone)}${releaseNode(`Server${profile ? ` · ${profile.environment}` : ""}`, serverState.liveSha ? shortSha(serverState.liveSha) : "Unknown", profile ? (serverState.checkedAt ? `checked ${formatDate(serverState.checkedAt)}` : "not checked") : "No deployment profile", serverTone)}</div>
|
||||
<nav class="tabs">${[
|
||||
@@ -3244,6 +3257,27 @@ document.addEventListener("keydown", (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("pointermove", (event) => {
|
||||
const illustration = event.target.closest?.("[data-project-illustration]");
|
||||
if (!illustration) return;
|
||||
const bounds = illustration.getBoundingClientRect();
|
||||
illustration.style.setProperty(
|
||||
"--tilt-x",
|
||||
`${((event.clientY - bounds.top) / bounds.height - 0.5) * -7}deg`,
|
||||
);
|
||||
illustration.style.setProperty(
|
||||
"--tilt-y",
|
||||
`${((event.clientX - bounds.left) / bounds.width - 0.5) * 9}deg`,
|
||||
);
|
||||
});
|
||||
|
||||
document.addEventListener("pointerout", (event) => {
|
||||
const illustration = event.target.closest?.("[data-project-illustration]");
|
||||
if (!illustration || illustration.contains(event.relatedTarget)) return;
|
||||
illustration.style.removeProperty("--tilt-x");
|
||||
illustration.style.removeProperty("--tilt-y");
|
||||
});
|
||||
|
||||
window.addEventListener("error", (event) => {
|
||||
window.forgeflow
|
||||
.reportRendererEvent?.("error", "uncaught-error", {
|
||||
|
||||
Reference in New Issue
Block a user