Release ForgeFlow 0.8.6 premium code canvas
This commit is contained in:
+53
-14
@@ -773,10 +773,25 @@ function releaseNode(label, value, description, tone = "") {
|
||||
return `<div class="release-node"><div class="release-label">${label}</div><div class="release-value"><span class="state-dot ${tone}"></span><strong>${escapeHtml(value)}</strong><span>${escapeHtml(description)}</span></div></div>`;
|
||||
}
|
||||
|
||||
function diffAtmosphere(diff) {
|
||||
if (!ui.selectedFile) return "";
|
||||
const lines = String(diff || "").split("\n");
|
||||
const additions = lines.filter(
|
||||
(line) => line.startsWith("+") && !line.startsWith("+++"),
|
||||
).length;
|
||||
const removals = lines.filter(
|
||||
(line) => line.startsWith("-") && !line.startsWith("---"),
|
||||
).length;
|
||||
const extension =
|
||||
String(ui.selectedFile).split(".").pop()?.slice(0, 8).toUpperCase() ||
|
||||
"FILE";
|
||||
return `<div class="diff-atmosphere ${lines.length > 34 ? "dense" : ""}" data-diff-atmosphere aria-hidden="true"><svg viewBox="0 0 360 260" role="presentation"><path class="code-route route-a" d="M38 195 C92 84 178 214 318 74"/><path class="code-route route-b" d="M52 74 C132 8 230 34 310 156"/><g class="code-card"><rect x="110" y="75" width="142" height="106" rx="18"/><path d="M136 108h90M136 128h58M136 148h76"/></g><g class="code-node node-one"><circle cx="48" cy="190" r="15"/><path d="m41 190 5 5 9-12"/></g><g class="code-node node-two"><circle cx="315" cy="76" r="13"/><path d="M308 76h14M315 69v14"/></g><circle class="code-packet packet-one" cx="0" cy="0" r="5"/><circle class="code-packet packet-two" cx="0" cy="0" r="4"/></svg><div class="diff-atmosphere-caption"><span>${escapeHtml(extension)} change map</span><strong><i>+${additions}</i><i>−${removals}</i></strong></div></div>`;
|
||||
}
|
||||
|
||||
function renderDiff(diff) {
|
||||
if (!diff)
|
||||
return '<div class="empty-state"><div class="empty-icon">↔</div><h3>No textual diff</h3><p>Select another file or open the project folder for binary changes.</p></div>';
|
||||
return escapeHtml(diff)
|
||||
const rendered = escapeHtml(diff)
|
||||
.split("\n")
|
||||
.map((line) => {
|
||||
const type =
|
||||
@@ -790,6 +805,7 @@ function renderDiff(diff) {
|
||||
return `<span class="diff-line ${type}">${line || " "}</span>`;
|
||||
})
|
||||
.join("");
|
||||
return `${rendered}${diffAtmosphere(diff)}`;
|
||||
}
|
||||
function fileStatusCode(file) {
|
||||
if (file.conflict) return "U";
|
||||
@@ -3259,23 +3275,46 @@ 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`,
|
||||
);
|
||||
if (illustration) {
|
||||
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`,
|
||||
);
|
||||
}
|
||||
|
||||
const diffPanel = event.target.closest?.(".diff-panel");
|
||||
const atmosphere = diffPanel?.querySelector("[data-diff-atmosphere]");
|
||||
if (atmosphere) {
|
||||
const bounds = diffPanel.getBoundingClientRect();
|
||||
atmosphere.style.setProperty(
|
||||
"--diff-tilt-x",
|
||||
`${((event.clientY - bounds.top) / bounds.height - 0.5) * -3}deg`,
|
||||
);
|
||||
atmosphere.style.setProperty(
|
||||
"--diff-tilt-y",
|
||||
`${((event.clientX - bounds.left) / bounds.width - 0.5) * 4}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");
|
||||
if (illustration && !illustration.contains(event.relatedTarget)) {
|
||||
illustration.style.removeProperty("--tilt-x");
|
||||
illustration.style.removeProperty("--tilt-y");
|
||||
}
|
||||
|
||||
const diffPanel = event.target.closest?.(".diff-panel");
|
||||
if (diffPanel && !diffPanel.contains(event.relatedTarget)) {
|
||||
const atmosphere = diffPanel.querySelector("[data-diff-atmosphere]");
|
||||
atmosphere?.style.removeProperty("--diff-tilt-x");
|
||||
atmosphere?.style.removeProperty("--diff-tilt-y");
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("error", (event) => {
|
||||
|
||||
@@ -564,7 +564,7 @@
|
||||
await wait(80);
|
||||
snapshot();
|
||||
return {
|
||||
appVersion: "0.8.5-demo",
|
||||
appVersion: "0.8.6-demo",
|
||||
platform: "win32",
|
||||
state: clone(state),
|
||||
git: { available: true, version: "git version 2.47.3" },
|
||||
|
||||
+212
-4
@@ -970,27 +970,56 @@ select:focus-visible {
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
.file-row {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 34px;
|
||||
min-height: 38px;
|
||||
display: grid;
|
||||
grid-template-columns: 17px 17px minmax(0, 1fr) 16px;
|
||||
gap: 7px;
|
||||
align-items: center;
|
||||
padding: 3px 6px;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 7px;
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition:
|
||||
transform 160ms ease,
|
||||
border-color 160ms ease,
|
||||
background 160ms ease,
|
||||
box-shadow 160ms ease;
|
||||
}
|
||||
.file-row:hover {
|
||||
background: var(--surface-hover);
|
||||
color: var(--text);
|
||||
border-color: color-mix(in srgb, var(--primary) 18%, transparent);
|
||||
transform: translateX(2px);
|
||||
}
|
||||
.file-row.active {
|
||||
background: var(--primary-soft);
|
||||
background:
|
||||
linear-gradient(90deg, var(--primary-soft), transparent 110%),
|
||||
var(--surface-1);
|
||||
border-color: color-mix(in srgb, var(--primary) 36%, var(--line));
|
||||
box-shadow:
|
||||
inset 3px 0 0 var(--primary),
|
||||
0 7px 22px rgba(0, 0, 0, 0.12);
|
||||
color: var(--text);
|
||||
}
|
||||
.file-row > span:last-child {
|
||||
color: var(--text-faint);
|
||||
filter: drop-shadow(0 0 5px transparent);
|
||||
transition:
|
||||
color 160ms ease,
|
||||
filter 160ms ease;
|
||||
}
|
||||
.file-row:hover > span:last-child,
|
||||
.file-row.active > span:last-child {
|
||||
color: var(--primary);
|
||||
filter: drop-shadow(
|
||||
0 0 5px color-mix(in srgb, var(--primary) 45%, transparent)
|
||||
);
|
||||
}
|
||||
.file-row input {
|
||||
margin: 0;
|
||||
accent-color: var(--primary-strong);
|
||||
@@ -1003,6 +1032,12 @@ select:focus-visible {
|
||||
font-size: 11px;
|
||||
}
|
||||
.file-status {
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
border-radius: 5px;
|
||||
background: color-mix(in srgb, currentColor 11%, transparent);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 750;
|
||||
@@ -1017,6 +1052,7 @@ select:focus-visible {
|
||||
color: var(--danger);
|
||||
}
|
||||
.diff-panel {
|
||||
container-type: inline-size;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
display: grid;
|
||||
@@ -1041,6 +1077,8 @@ select:focus-visible {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.diff-view {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
overflow: auto;
|
||||
padding: 8px 0 36px;
|
||||
font-family: var(--font-mono);
|
||||
@@ -1048,12 +1086,179 @@ select:focus-visible {
|
||||
line-height: 19px;
|
||||
white-space: pre;
|
||||
tab-size: 2;
|
||||
background:
|
||||
radial-gradient(
|
||||
circle at 84% 72%,
|
||||
color-mix(in srgb, var(--primary) 8%, transparent),
|
||||
transparent 28%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 72% 88%,
|
||||
color-mix(in srgb, var(--success) 5%, transparent),
|
||||
transparent 24%
|
||||
);
|
||||
}
|
||||
.diff-line {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: block;
|
||||
min-height: 19px;
|
||||
padding: 0 14px;
|
||||
}
|
||||
.diff-atmosphere {
|
||||
--diff-tilt-x: 0deg;
|
||||
--diff-tilt-y: 0deg;
|
||||
position: absolute;
|
||||
right: clamp(24px, 7vw, 110px);
|
||||
bottom: clamp(28px, 8vh, 90px);
|
||||
z-index: 0;
|
||||
width: min(360px, 34vw);
|
||||
color: var(--primary);
|
||||
opacity: 0.38;
|
||||
pointer-events: none;
|
||||
transform: perspective(850px) rotateX(var(--diff-tilt-x))
|
||||
rotateY(var(--diff-tilt-y));
|
||||
transform-style: preserve-3d;
|
||||
transition:
|
||||
transform 220ms ease-out,
|
||||
opacity 180ms ease;
|
||||
}
|
||||
.diff-atmosphere.dense {
|
||||
opacity: 0.14;
|
||||
}
|
||||
.diff-atmosphere svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
.code-route {
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.2;
|
||||
stroke-dasharray: 4 8;
|
||||
opacity: 0.42;
|
||||
}
|
||||
.code-route.route-b {
|
||||
color: var(--success);
|
||||
}
|
||||
.code-card rect {
|
||||
fill: color-mix(in srgb, var(--surface-2) 72%, transparent);
|
||||
stroke: color-mix(in srgb, var(--primary) 60%, var(--line));
|
||||
stroke-width: 1.2;
|
||||
filter: drop-shadow(0 18px 28px rgba(0, 0, 0, 0.24));
|
||||
}
|
||||
.code-card path {
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-width: 4;
|
||||
opacity: 0.62;
|
||||
}
|
||||
.code-node circle {
|
||||
fill: var(--surface-2);
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
.code-node path {
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 2;
|
||||
}
|
||||
.node-one {
|
||||
color: var(--success);
|
||||
animation: code-node-float 5s ease-in-out infinite;
|
||||
}
|
||||
.node-two {
|
||||
animation: code-node-float 5s ease-in-out -2.5s infinite;
|
||||
}
|
||||
.code-packet {
|
||||
fill: var(--primary);
|
||||
filter: drop-shadow(0 0 8px currentColor);
|
||||
offset-path: path("M38 195 C92 84 178 214 318 74");
|
||||
animation: code-packet-travel 5.4s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||||
}
|
||||
.code-packet.packet-two {
|
||||
fill: var(--success);
|
||||
offset-path: path("M52 74 C132 8 230 34 310 156");
|
||||
animation-delay: -2.7s;
|
||||
}
|
||||
.diff-atmosphere-caption {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: -10px 42px 0;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid color-mix(in srgb, var(--primary) 32%, transparent);
|
||||
color: var(--text-muted);
|
||||
font: 700 9px/1 var(--font-mono);
|
||||
letter-spacing: 0.11em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.diff-atmosphere-caption strong {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.diff-atmosphere-caption i {
|
||||
color: var(--success);
|
||||
font-style: normal;
|
||||
}
|
||||
.diff-atmosphere-caption i + i {
|
||||
color: var(--danger);
|
||||
}
|
||||
@keyframes code-packet-travel {
|
||||
0% {
|
||||
offset-distance: 0%;
|
||||
opacity: 0;
|
||||
}
|
||||
12%,
|
||||
82% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
offset-distance: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes code-node-float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
}
|
||||
html[data-theme="light"] .diff-view {
|
||||
background:
|
||||
radial-gradient(
|
||||
circle at 84% 72%,
|
||||
rgba(72, 92, 220, 0.12),
|
||||
transparent 30%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 72% 88%,
|
||||
rgba(15, 148, 108, 0.08),
|
||||
transparent 25%
|
||||
),
|
||||
linear-gradient(
|
||||
135deg,
|
||||
rgba(248, 251, 255, 0.88),
|
||||
rgba(239, 245, 255, 0.62)
|
||||
);
|
||||
}
|
||||
html[data-theme="light"] .diff-atmosphere {
|
||||
opacity: 0.46;
|
||||
}
|
||||
html[data-theme="light"] .diff-atmosphere.dense {
|
||||
opacity: 0.18;
|
||||
}
|
||||
@container (max-width: 560px) {
|
||||
.diff-atmosphere {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.diff-line.add {
|
||||
background: rgba(38, 166, 115, 0.14);
|
||||
color: #8ef0c6;
|
||||
@@ -3408,6 +3613,9 @@ html[data-theme="light"] .visual-page-header {
|
||||
.project-illustration svg {
|
||||
transform: none !important;
|
||||
}
|
||||
.diff-atmosphere {
|
||||
transform: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
|
||||
Reference in New Issue
Block a user