Replace the bulky hero installers with a compact platform switcher, wrapping command, and copy action

Hop-State: A_06FN6S8S3T184C0AS6MXQ08
Hop-Proposal: R_06FN6S5PSBAXTT4CDRPQS0R
Hop-Task: T_06FN6N560GHE00H1ACBKR8G
Hop-Attempt: AT_06FN6N560G6CPSCDTN8C48R
This commit is contained in:
Hop
2026-07-11 15:56:02 -07:00
parent fee4f6dd31
commit 0cb027737e
3 changed files with 202 additions and 74 deletions
@@ -305,6 +305,72 @@
load(); load();
} }
async function copyToClipboard(value) {
if (navigator.clipboard?.writeText) {
try {
await navigator.clipboard.writeText(value);
return true;
} catch {
// Fall back for browsers that block clipboard access outside a secure context.
}
}
const input = document.createElement('textarea');
input.value = value;
input.setAttribute('readonly', '');
input.style.position = 'fixed';
input.style.opacity = '0';
document.body.append(input);
input.select();
input.setSelectionRange(0, value.length);
const copied = document.execCommand('copy');
input.remove();
return copied;
}
function bindInstallationSwitchers() {
for (const switcher of document.querySelectorAll('.hop-agent-install-shell')) {
if (switcher.dataset.hopInstallBound === 'true') continue;
switcher.dataset.hopInstallBound = 'true';
const buttons = [...switcher.querySelectorAll('[data-hop-install-command]')];
const output = switcher.querySelector('[data-hop-install-command-output]');
const copyButton = switcher.querySelector('[data-hop-copy]');
const status = copyButton ? document.getElementById(copyButton.getAttribute('aria-describedby')) : null;
for (const button of buttons) {
button.addEventListener('click', () => {
for (const option of buttons) option.setAttribute('aria-pressed', String(option === button));
if (output) output.textContent = button.dataset.hopInstallCommand;
if (copyButton) copyButton.setAttribute('aria-label', `Copy ${button.dataset.hopInstallPlatform} installation command`);
if (status) status.textContent = '';
});
}
}
}
function bindInstallationCopyButtons() {
for (const button of document.querySelectorAll('[data-hop-copy]')) {
if (button.dataset.hopCopyBound === 'true') continue;
button.dataset.hopCopyBound = 'true';
button.addEventListener('click', async () => {
const command = button.closest('.hop-agent-install-command')?.querySelector('code')?.textContent?.trim();
const status = document.getElementById(button.getAttribute('aria-describedby'));
if (!command) return;
button.disabled = true;
button.textContent = 'Copying…';
const copied = await copyToClipboard(command);
button.disabled = false;
button.textContent = copied ? 'Copied' : 'Retry';
if (status) status.textContent = copied ? 'Command copied to clipboard.' : 'Could not copy automatically. Select the command and copy it.';
window.setTimeout(() => {
button.textContent = 'Copy';
if (status) status.textContent = '';
}, 2400);
});
}
}
function replaceBrandImages() { function replaceBrandImages() {
const upstreamBrandAsset = /\/img\/(?:avatar_default\.png|logo\.png|logo\.svg)(?:\?.*)?$/; const upstreamBrandAsset = /\/img\/(?:avatar_default\.png|logo\.png|logo\.svg)(?:\?.*)?$/;
for (const image of document.querySelectorAll('img[src]')) { for (const image of document.querySelectorAll('img[src]')) {
@@ -322,6 +388,8 @@
addPromptsNavigation(); addPromptsNavigation();
addWorkflowSummary(); addWorkflowSummary();
renderPromptPage(); renderPromptPage();
bindInstallationSwitchers();
bindInstallationCopyButtons();
const title = replacePhrases(document.title); const title = replacePhrases(document.title);
if (title !== document.title) document.title = title; if (title !== document.title) document.title = title;
document.documentElement.dataset.hopNative = 'true'; document.documentElement.dataset.hopNative = 'true';
+1 -1
View File
@@ -1,3 +1,3 @@
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/hop-home.css?v=4"> <link rel="stylesheet" href="{{AssetUrlPrefix}}/css/hop-home.css?v=4">
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/hop-prompts.css?v=1"> <link rel="stylesheet" href="{{AssetUrlPrefix}}/css/hop-prompts.css?v=1">
<script src="{{AssetUrlPrefix}}/js/hop-native.js?v=9"></script> <script src="{{AssetUrlPrefix}}/js/hop-native.js?v=10"></script>
+126 -66
View File
@@ -242,37 +242,121 @@
font-weight: 550; font-weight: 550;
} }
.hop-agent-install { .hop-agent-installs {
border-top: 1px solid var(--color-secondary);
margin-top: 1.5rem;
max-width: 100%;
padding-top: 1rem;
}
.hop-agent-install-heading {
align-items: baseline;
display: flex;
gap: 1rem;
justify-content: space-between;
}
.hop-agent-install-shell {
border: 1px solid var(--color-secondary);
border-radius: var(--border-radius);
margin-top: 0.7rem;
min-width: 0;
overflow: hidden;
}
.hop-agent-install-tabs {
align-items: center;
display: flex;
gap: 0.25rem;
padding: 0.25rem;
}
.hop-agent-install-tab {
background: transparent;
border: 0;
border-radius: calc(var(--border-radius) - 2px);
color: var(--color-text-light-2);
cursor: pointer;
font: inherit;
font-size: 0.72rem;
font-weight: 650;
line-height: 1;
padding: 0.55rem 0.7rem;
}
.hop-agent-install-tab[aria-pressed="true"] {
background: color-mix(in srgb, var(--color-primary) 18%, transparent);
color: var(--color-text);
}
.hop-agent-install-tab:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 1px;
}
.hop-agent-install-command {
align-items: center;
background: color-mix(in srgb, var(--color-secondary) 42%, transparent);
border-top: 1px solid var(--color-secondary); border-top: 1px solid var(--color-secondary);
display: grid; display: grid;
gap: clamp(3rem, 7vw, 6rem); gap: 0.75rem;
grid-template-columns: minmax(220px, 0.7fr) minmax(0, 1.3fr); grid-template-columns: minmax(0, 1fr) auto;
margin-top: clamp(3.5rem, 5vw, 5rem); min-width: 0;
padding-top: clamp(2.25rem, 3.5vw, 3.5rem); padding: 0.75rem 0.8rem;
} }
.hop-agent-install-copy h2 { .hop-agent-copy-button {
font-size: clamp(2.2rem, 4vw, 3.6rem); background: transparent;
border: 1px solid var(--color-secondary);
border-radius: var(--border-radius);
color: var(--color-text);
cursor: pointer;
font: inherit;
font-size: 0.78rem;
font-weight: 650; font-weight: 650;
letter-spacing: -0.045em; line-height: 1;
line-height: 1.04; padding: 0.5rem 0.65rem;
margin-top: 0.9rem;
} }
.hop-agent-install-copy > p:last-of-type { .hop-agent-copy-button:hover {
color: var(--color-text-light-2) !important; background: color-mix(in srgb, var(--color-primary) 16%, transparent);
font-size: 1rem; }
line-height: 1.6;
margin-top: 1.2rem !important; .hop-agent-copy-button:focus-visible {
max-width: 42ch; outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
.hop-agent-install-command code {
color: var(--color-text);
display: block;
font-family: var(--fonts-monospace);
font-size: clamp(0.72rem, 1.12vw, 0.84rem);
line-height: 1.45;
min-width: 0;
overflow-wrap: anywhere;
white-space: pre-wrap;
word-break: break-word;
}
.hop-agent-copy-status {
color: var(--color-text-light-2);
display: block;
font-size: 0.78rem;
line-height: 1.3;
margin-top: 0.45rem;
}
.hop-agent-copy-status:empty {
display: none;
} }
.hop-agent-repo-link { .hop-agent-repo-link {
align-items: center; align-items: center;
display: inline-flex; display: inline-flex;
font-weight: 650; font-size: 0.84rem;
font-weight: 600;
gap: 0.45rem; gap: 0.45rem;
margin-top: 1.5rem;
} }
.hop-agent-repo-link::after { .hop-agent-repo-link::after {
@@ -280,29 +364,6 @@
font-size: 0.9em; font-size: 0.9em;
} }
.hop-agent-install-list {
border-top: 1px solid var(--color-secondary);
}
.hop-agent-install-command {
border-bottom: 1px solid var(--color-secondary);
padding: 1.45rem 0;
}
.hop-agent-install-command code {
background: color-mix(in srgb, var(--color-secondary) 42%, transparent);
border-radius: var(--border-radius);
color: var(--color-text);
display: block;
font-family: var(--fonts-monospace);
font-size: clamp(0.78rem, 1.35vw, 0.94rem);
line-height: 1.55;
margin-top: 0.85rem;
overflow-x: auto;
padding: 0.85rem 1rem;
white-space: pre;
}
.hop-agent-finish { .hop-agent-finish {
align-items: end; align-items: end;
border-top: 1px solid var(--color-secondary); border-top: 1px solid var(--color-secondary);
@@ -345,10 +406,6 @@
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.hop-agent-install {
grid-template-columns: 1fr;
}
.hop-agent-flow .hop-agent-section-heading { .hop-agent-flow .hop-agent-section-heading {
max-width: 620px; max-width: 620px;
} }
@@ -454,9 +511,14 @@
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.hop-agent-install-command code { .hop-agent-install-heading {
font-size: 0.76rem; align-items: center;
} }
.hop-agent-install-command {
align-items: start;
}
} }
</style> </style>
<main id="hop-main" tabindex="-1" role="main" aria-label="Hop, agent-first version control" class="page-content hop-agent-home"> <main id="hop-main" tabindex="-1" role="main" aria-label="Hop, agent-first version control" class="page-content hop-agent-home">
@@ -474,6 +536,23 @@
<a class="ui basic button" href="#why-hop">Why use Hop?</a> <a class="ui basic button" href="#why-hop">Why use Hop?</a>
{{end}} {{end}}
</div> </div>
<div class="hop-agent-installs" aria-label="Install Hop">
<div class="hop-agent-install-heading">
<p class="hop-agent-label">Install Hop</p>
<a class="hop-agent-repo-link" href="https://githop.xyz/GnosysLabs/Hop" target="_blank" rel="noreferrer">Repository</a>
</div>
<div class="hop-agent-install-shell">
<div class="hop-agent-install-tabs" role="group" aria-label="Installation platform">
<button class="hop-agent-install-tab" type="button" aria-pressed="true" data-hop-install-command="curl -fsSL https://githop.xyz/GnosysLabs/Hop/raw/branch/main/scripts/install.sh | sh" data-hop-install-platform="macOS and Linux">macOS + Linux</button>
<button class="hop-agent-install-tab" type="button" aria-pressed="false" data-hop-install-command="irm https://githop.xyz/GnosysLabs/Hop/raw/branch/main/scripts/install.ps1 | iex" data-hop-install-platform="Windows PowerShell">Windows</button>
</div>
<div class="hop-agent-install-command">
<code data-hop-install-command-output>curl -fsSL https://githop.xyz/GnosysLabs/Hop/raw/branch/main/scripts/install.sh | sh</code>
<button class="hop-agent-copy-button" type="button" data-hop-copy aria-label="Copy macOS and Linux installation command" aria-describedby="hop-install-status">Copy</button>
</div>
</div>
<span class="hop-agent-copy-status" id="hop-install-status" role="status" aria-live="polite"></span>
</div>
<p class="hop-agent-note">Git stays underneath for compatibility. The mechanics disappear from your workflow.</p> <p class="hop-agent-note">Git stays underneath for compatibility. The mechanics disappear from your workflow.</p>
</div> </div>
<figure class="hop-agent-mascot"> <figure class="hop-agent-mascot">
@@ -534,25 +613,6 @@
</div> </div>
</section> </section>
<section class="hop-agent-install" id="install-hop" aria-labelledby="hop-agent-install-title">
<div class="hop-agent-install-copy">
<p class="hop-agent-label">Install Hop</p>
<h2 id="hop-agent-install-title">One install. No Git busywork.</h2>
<p>Install the Hop CLI, then tell your agents what to build. Hop handles isolated workspaces, checkpoints, reconciliation, and landing.</p>
<a class="hop-agent-repo-link" href="https://githop.xyz/GnosysLabs/Hop" target="_blank" rel="noreferrer">Official Hop repository</a>
</div>
<div class="hop-agent-install-list" aria-label="Hop installation commands">
<div class="hop-agent-install-command">
<p class="hop-agent-label">macOS and Linux</p>
<code>curl -fsSL https://githop.xyz/GnosysLabs/Hop/raw/branch/main/scripts/install.sh | sh</code>
</div>
<div class="hop-agent-install-command">
<p class="hop-agent-label">Windows PowerShell</p>
<code>irm https://githop.xyz/GnosysLabs/Hop/raw/branch/main/scripts/install.ps1 | iex</code>
</div>
</div>
</section>
<section class="hop-agent-finish" aria-labelledby="hop-agent-finish-title"> <section class="hop-agent-finish" aria-labelledby="hop-agent-finish-title">
<div> <div>
<h2 id="hop-agent-finish-title">Git compatibility without Git busywork.</h2> <h2 id="hop-agent-finish-title">Git compatibility without Git busywork.</h2>