suse
This commit is contained in:
1 parent
1f0daa0679
commit
f86a62b8b1
19 files changed
+389
-73
No files matched your search
+5
-2
@@ -26,9 +26,10 @@ PORT = int(os.environ.get("DASHBOARD_PORT", "8000"))
|
||||
CACHE_SECONDS = max(1, int(os.environ.get("DASHBOARD_CACHE_SECONDS", "15")))
|
||||
MAX_PACKAGES = 5000
|
||||
|
||||
SITES = ("linux", "opnsense", "freebsd")
|
||||
SITES = ("linux", "suse", "opnsense", "freebsd")
|
||||
META_PATHS = {
|
||||
"linux": Path("LINUX-BUILD-INFO.txt"),
|
||||
"suse": Path("SUSE-BUILD-INFO.txt"),
|
||||
"opnsense": Path("opnsense/BUILD-INFO.txt"),
|
||||
"freebsd": Path("freebsd/BUILD-INFO.txt"),
|
||||
}
|
||||
@@ -37,6 +38,7 @@ REPO_URLS = {
|
||||
"opnsense": os.environ.get("OPNSENSE_REPOSITORY_URL", "http://localhost:18766").rstrip("/"),
|
||||
}
|
||||
REPO_URLS["freebsd"] = REPO_URLS["opnsense"] + "/freebsd"
|
||||
REPO_URLS["suse"] = REPO_URLS["linux"] + "/suse"
|
||||
|
||||
DEB_FILENAME = re.compile(r"^(?P<name>.+?)_(?P<version>[^_]+)_(?P<arch>[^_]+)\.deb$")
|
||||
RPM_FILENAME = re.compile(
|
||||
@@ -98,7 +100,7 @@ def publication_info(current: Path, channel: str) -> dict[str, object]:
|
||||
"built_at": None,
|
||||
"date_source": "unknown",
|
||||
}
|
||||
if channel == "linux" and info["app_version"]:
|
||||
if channel in ("linux", "suse") and info["app_version"]:
|
||||
info["package_version"] = f"{info['app_version']}-{info['package_release']}" if info["package_release"] else info["app_version"]
|
||||
|
||||
stamp = raw.get("built_at", "")
|
||||
@@ -189,6 +191,7 @@ def generate_catalog(repository: Path = REPOSITORY) -> dict[str, object]:
|
||||
folders = (
|
||||
("linux", "deb", "linux", current / "apt" / "pool", "*.deb"),
|
||||
("linux", "rpm", "linux", current / "rpm" / "x86_64", "*.rpm"),
|
||||
("suse", "rpm", "suse", current / "suse" / "x86_64", "*.rpm"),
|
||||
("opnsense", "pkg", "opnsense", current / "opnsense", "*.pkg"),
|
||||
("freebsd", "pkg", "freebsd", current / "freebsd", "*.pkg"),
|
||||
)
|
||||
|
||||
+32
-9
@@ -3,8 +3,8 @@
|
||||
'use strict';
|
||||
|
||||
const el = (id) => document.getElementById(id);
|
||||
const CHANNEL_LABELS = {linux:'Linux',opnsense:'OPNsense',freebsd:'FreeBSD'};
|
||||
const INSTALL_NAMES = {deb:'Debian / Ubuntu',rpm:'RHEL / Rocky / Alma / Fedora',opnsense:'OPNsense',freebsd:'FreeBSD native'};
|
||||
const CHANNEL_LABELS = {linux:'Linux',suse:'SUSE / openSUSE',opnsense:'OPNsense',freebsd:'FreeBSD'};
|
||||
const INSTALL_NAMES = {deb:'Debian / Ubuntu',rpm:'RHEL / Rocky / Alma / Fedora',suse:'SUSE / openSUSE / Leap',opnsense:'OPNsense',freebsd:'FreeBSD native'};
|
||||
const SECTION_LABELS = {overview:'Overview',packages:'Packages & versions',install:'Installation',repository:'Repositories'};
|
||||
const esc = (value) => String(value ?? '').replace(/[&<>"']/g, (char) => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[char]));
|
||||
const collator = new Intl.Collator('en', {numeric:true,sensitivity:'base'});
|
||||
@@ -78,11 +78,12 @@
|
||||
function buildCard(build, channel) {
|
||||
const live = !!build?.published;
|
||||
const commit = build?.source_commit ? build.source_commit.slice(0,9) : '—';
|
||||
const subtitle = channel === 'linux' ? 'APT / DNF · amd64 + x86_64' : channel === 'opnsense'
|
||||
const subtitle = channel === 'linux' ? 'APT / DNF · amd64 + x86_64' : channel === 'suse'
|
||||
? 'RPM / Zypper · x86_64' : channel === 'opnsense'
|
||||
? `PKG · ${build?.opnsense_series || 'FreeBSD'}` : `PKG · ${build?.freebsd_abi || 'Native'}`;
|
||||
const version = build?.package_version || (live ? build?.app_version : '') || '—';
|
||||
return `<article class="build-card${live ? '' : ' off'}">
|
||||
<div class="build-card-top"><span>${esc(CHANNEL_LABELS[channel].toUpperCase())} / ${channel === 'linux' ? 'SIGNED' : 'PKG'}</span><span class="pill ${live ? 'live' : 'missing'}">${live ? 'PUBLISHED' : 'NOT BUILT'}</span></div>
|
||||
<div class="build-card-top"><span>${esc(CHANNEL_LABELS[channel].toUpperCase())} / ${['linux','suse'].includes(channel) ? 'SIGNED' : 'PKG'}</span><span class="pill ${live ? 'live' : 'missing'}">${live ? 'PUBLISHED' : 'NOT BUILT'}</span></div>
|
||||
<div class="build-card-version">${esc(version)}</div><div class="build-card-sub">${esc(subtitle)}</div>
|
||||
<div class="build-card-details"><div><small>BUILD DATE</small><strong title="${esc(dateLabel(build?.date_source))}">${esc(formatDate(build?.built_at))}</strong></div><div><small>COMMIT</small><strong class="commit">${esc(commit)}</strong></div></div>
|
||||
</article>`;
|
||||
@@ -109,7 +110,7 @@
|
||||
setText('hero-commit', main?.source_commit ? main.source_commit.slice(0,12) : '—');
|
||||
el('hero-date').title = dateLabel(main?.date_source);
|
||||
setText('stat-packages', formatNumber.format(data.summary?.packages_count || 0));
|
||||
setText('stat-channels', `${data.summary?.channels_published || 0} / 3`);
|
||||
setText('stat-channels', `${data.summary?.channels_published || 0} / 4`);
|
||||
setText('stat-date', formatShortDate(data.summary?.latest_build_at));
|
||||
setText('stat-version', heroVersion);
|
||||
setText('stat-release', main?.package_version ? `Package: ${main.package_version}` : 'No release published yet');
|
||||
@@ -121,8 +122,8 @@
|
||||
el('sidebar-status').classList.toggle('waiting', !ready);
|
||||
el('sidebar-status').querySelector('span').textContent = ready ? 'REPOSITORY ONLINE' : 'WAITING FOR DATA';
|
||||
const side = el('side-channels');
|
||||
side.innerHTML = ['linux','opnsense','freebsd'].map((channel) => `<span class="side-channel${data.builds[channel]?.published ? '' : ' disabled'}"><i class="tiny-dot"></i>${esc(CHANNEL_LABELS[channel])}<small>${channel === 'linux' ? 'APT / DNF' : 'PKG'}</small></span>`).join('');
|
||||
el('build-grid').innerHTML = ['linux','opnsense','freebsd'].map((channel) => buildCard(data.builds[channel],channel)).join('');
|
||||
side.innerHTML = ['linux','suse','opnsense','freebsd'].map((channel) => `<span class="side-channel${data.builds[channel]?.published ? '' : ' disabled'}"><i class="tiny-dot"></i>${esc(CHANNEL_LABELS[channel])}<small>${channel === 'linux' ? 'APT / DNF' : channel === 'suse' ? 'RPM / Zypper' : 'PKG'}</small></span>`).join('');
|
||||
el('build-grid').innerHTML = ['linux','suse','opnsense','freebsd'].map((channel) => buildCard(data.builds[channel],channel)).join('');
|
||||
const recent = data.packages.filter((pkg) => state.site === 'linux' || pkg.channel === state.site).slice(0,6);
|
||||
el('recent-rows').innerHTML = recent.length ? recent.map((pkg) => tableRow(pkg,true)).join('') : '<tr><td colspan="5" class="empty-table">No packages published yet. The catalog will populate after the first build.</td></tr>';
|
||||
}
|
||||
@@ -157,6 +158,7 @@
|
||||
function instructions(kind, data) {
|
||||
const urls = data.repository_urls || {};
|
||||
const linux = origin(urls.linux);
|
||||
const suse = origin(urls.suse || `${linux}/suse`);
|
||||
const opnsense = origin(urls.opnsense);
|
||||
const freebsd = origin(urls.freebsd);
|
||||
const distribution = data.apt_distribution || 'stable';
|
||||
@@ -204,6 +206,21 @@
|
||||
].join('\n'),
|
||||
};
|
||||
}
|
||||
if (kind === 'suse') {
|
||||
return {
|
||||
description:'Add the signed RPM repository with Zypper on SUSE Linux Enterprise, openSUSE Leap or Tumbleweed.',
|
||||
signature:'GPG SIGNED',
|
||||
note:'x86_64. Minimum glibc: 2.34; intended for SLES 15 SP6+, SLES 16+, Leap 15.6+, and Tumbleweed. Check Python >= 3.10 dependencies.',
|
||||
reference:`${suse}/x86_64/repodata/repomd.xml`,
|
||||
agent:'sudo zypper install rustproxy-docker-agent',
|
||||
code:[
|
||||
`sudo rpm --import ${linux}/repo-key.gpg`,
|
||||
`sudo zypper addrepo --refresh --gpgcheck ${suse}/x86_64/ rustproxy-suse`,
|
||||
'sudo zypper refresh rustproxy-suse',
|
||||
'sudo zypper install rustproxy',
|
||||
].join('\n'),
|
||||
};
|
||||
}
|
||||
if (kind === 'opnsense') {
|
||||
return {
|
||||
description:'Fetch the pkg repository configuration and install the os-rustproxy plugin.',
|
||||
@@ -252,7 +269,7 @@
|
||||
setText('install-command', instructionsData.code);
|
||||
setText('install-note', instructionsData.note);
|
||||
// Docker discovery agent is only built for Linux DEB/RPM.
|
||||
const hasDockerAgent = (kind === 'deb' || kind === 'rpm') && !!instructionsData.agent;
|
||||
const hasDockerAgent = (kind === 'deb' || kind === 'rpm' || kind === 'suse') && !!instructionsData.agent;
|
||||
el('agent-card').hidden = !hasDockerAgent;
|
||||
el('install-extra-grid').classList.toggle('single-card', !hasDockerAgent);
|
||||
setText('trust-index', hasDockerAgent ? '02' : '01');
|
||||
@@ -279,6 +296,12 @@
|
||||
{name:'RPM repomd.xml',url:`${url.linux}/rpm/x86_64/repodata/repomd.xml`},
|
||||
{name:'Build info',url:`${url.linux}/LINUX-BUILD-INFO.txt`},
|
||||
],true),
|
||||
endpointsCard('SUSE / openSUSE','GPG SIGNED',url.suse,[
|
||||
{name:'GPG public key',url:`${url.linux}/repo-key.gpg`},
|
||||
{name:'RPM repomd.xml',url:`${url.suse}/x86_64/repodata/repomd.xml`},
|
||||
{name:'Metadata signature',url:`${url.suse}/x86_64/repodata/repomd.xml.asc`},
|
||||
{name:'Build info',url:`${url.linux}/SUSE-BUILD-INFO.txt`},
|
||||
],true),
|
||||
endpointsCard('OPNsense','UNSIGNED PKG',url.opnsense,[
|
||||
{name:'RustProxy.conf',url:`${url.opnsense}/RustProxy.conf`},
|
||||
{name:'meta.conf',url:`${url.opnsense}/meta.conf`},
|
||||
@@ -292,7 +315,7 @@
|
||||
{name:'Build info',url:`${url.freebsd}/BUILD-INFO.txt`},
|
||||
],false),
|
||||
].join('');
|
||||
el('metadata-table').innerHTML = ['linux','opnsense','freebsd'].map((channel) => {
|
||||
el('metadata-table').innerHTML = ['linux','suse','opnsense','freebsd'].map((channel) => {
|
||||
const b = data.builds[channel] || {};
|
||||
const rows = [
|
||||
['APPLICATION VERSION',b.app_version || '—','latest-value'],
|
||||
|
||||
@@ -27,12 +27,13 @@
|
||||
<div class="sidebar-label sidebar-label--second">AVAILABLE CHANNELS</div>
|
||||
<div class="side-channels" id="side-channels">
|
||||
<span class="side-channel"><i class="tiny-dot"></i> Linux <small>APT / DNF</small></span>
|
||||
<span class="side-channel"><i class="tiny-dot"></i> SUSE / openSUSE <small>RPM / Zypper</small></span>
|
||||
<span class="side-channel"><i class="tiny-dot"></i> OPNsense <small>PKG</small></span>
|
||||
<span class="side-channel"><i class="tiny-dot"></i> FreeBSD <small>PKG</small></span>
|
||||
</div>
|
||||
<div class="sidebar-bottom">
|
||||
<div class="small-label">REPOSITORY ENGINE</div>
|
||||
<p>Python / HTTP API<br>Nginx / Signed APT + RPM<br>FreeBSD pkg catalog</p>
|
||||
<p>Python / HTTP API<br>Nginx / Signed APT + RPM + SUSE<br>FreeBSD pkg catalog</p>
|
||||
<div class="local-tag" id="sidebar-status"><i></i><span>WAITING FOR DATA</span></div>
|
||||
<div class="copyright">© RustProxy <span id="year"></span></div>
|
||||
</div>
|
||||
@@ -79,7 +80,7 @@
|
||||
<div class="pipeline-connector"></div>
|
||||
<div class="pipeline-step"><span class="step-index">02</span><span class="step-info"><b>Build / package</b><small>Rust + Go + FreeBSD</small></span><span class="step-right">CI <span>↗</span></span></div>
|
||||
<div class="pipeline-connector"></div>
|
||||
<div class="pipeline-step"><span class="step-index">03</span><span class="step-info"><b>Repository publish</b><small>APT / RPM / PKG</small></span><span class="step-right step-success">LIVE <span>●</span></span></div>
|
||||
<div class="pipeline-step"><span class="step-index">03</span><span class="step-info"><b>Repository publish</b><small>APT / RPM / Zypper / PKG</small></span><span class="step-right step-success">LIVE <span>●</span></span></div>
|
||||
</div>
|
||||
<div class="pipeline-footer">Last sync <span id="pipeline-updated">—</span></div>
|
||||
</div>
|
||||
@@ -87,7 +88,7 @@
|
||||
|
||||
<div class="stats-grid" aria-label="Repository statistics">
|
||||
<div class="stat"><span>01 / CATALOG PACKAGES</span><strong id="stat-packages">—</strong><small>All published artifacts</small></div>
|
||||
<div class="stat"><span>02 / ACTIVE CHANNELS</span><strong id="stat-channels">—</strong><small>Linux · OPNsense · FreeBSD</small></div>
|
||||
<div class="stat"><span>02 / ACTIVE CHANNELS</span><strong id="stat-channels">—</strong><small>Linux · SUSE · OPNsense · FreeBSD</small></div>
|
||||
<div class="stat"><span>03 / LATEST BUILD</span><strong class="stat-date" id="stat-date">—</strong><small id="stat-date-sub">Latest publication time</small></div>
|
||||
<div class="stat"><span>04 / CURRENT VERSION</span><strong id="stat-version">—</strong><small id="stat-release">Application version</small></div>
|
||||
</div>
|
||||
@@ -103,16 +104,16 @@
|
||||
|
||||
<section class="view" id="view-packages" aria-labelledby="packages-title" hidden>
|
||||
<div class="page-head compact-head"><div><div class="eyebrow"><span class="eyebrow-line"></span> ARTIFACT EXPLORER <span class="eyebrow-separator">/</span> VERSIONS</div><h1 id="packages-title">Package <em>catalog.</em></h1><p class="lead">Search, filter, sort, and download published files. All details are read directly from the current repository.</p></div><div class="count-pill" id="packages-total">0 packages</div></div>
|
||||
<div class="filter-panel"><div class="search-field"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m16.5 16.5 4 4"/></svg><input id="search-input" type="search" placeholder="Search by name, version, architecture..." aria-label="Search packages" autocomplete="off"></div><label class="filter-input">CHANNEL<select id="filter-channel"><option value="all">All</option><option value="linux">Linux</option><option value="opnsense">OPNsense</option><option value="freebsd">FreeBSD</option></select></label><label class="filter-input">FORMAT<select id="filter-format"><option value="all">All</option><option value="DEB">DEB</option><option value="RPM">RPM</option><option value="PKG">PKG</option></select></label><label class="filter-input">SORT BY<select id="filter-sort"><option value="date">Newest first</option><option value="version">Version ↓</option><option value="name">Name A–Z</option><option value="size">Size ↓</option></select></label></div>
|
||||
<div class="filter-panel"><div class="search-field"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m16.5 16.5 4 4"/></svg><input id="search-input" type="search" placeholder="Search by name, version, architecture..." aria-label="Search packages" autocomplete="off"></div><label class="filter-input">CHANNEL<select id="filter-channel"><option value="all">All</option><option value="linux">Linux</option><option value="suse">SUSE / openSUSE</option><option value="opnsense">OPNsense</option><option value="freebsd">FreeBSD</option></select></label><label class="filter-input">FORMAT<select id="filter-format"><option value="all">All</option><option value="DEB">DEB</option><option value="RPM">RPM</option><option value="PKG">PKG</option></select></label><label class="filter-input">SORT BY<select id="filter-sort"><option value="date">Newest first</option><option value="version">Version ↓</option><option value="name">Name A–Z</option><option value="size">Size ↓</option></select></label></div>
|
||||
<div class="result-topline"><span id="filter-count">Loading…</span><span>Versions and dates are read from packages and build metadata</span></div>
|
||||
<div class="card catalog-card"><div class="table-scroller"><table class="data-table data-table--catalog"><thead><tr><th>PACKAGE</th><th>CHANNEL</th><th>VERSION</th><th>BUILD DATE</th><th>SIZE</th><th>DOWNLOAD</th></tr></thead><tbody id="catalog-rows"><tr><td colspan="6" class="empty-table">Loading data…</td></tr></tbody></table></div><div class="catalog-bottom"><span id="result-range">—</span><button class="quiet show-more" id="show-more" hidden>Load 25 more ↓</button></div></div>
|
||||
</section>
|
||||
|
||||
<section class="view" id="view-install" aria-labelledby="install-title" hidden>
|
||||
<div class="page-head compact-head"><div><div class="eyebrow"><span class="eyebrow-line"></span> GET STARTED <span class="eyebrow-separator">/</span> INSTALLATION</div><h1 id="install-title">Install <em>RustProxy.</em></h1><p class="lead">Ready-to-run commands to add the repository and install RustProxy. Select a platform and copy the commands to your terminal.</p></div></div>
|
||||
<div class="install-tabs" role="tablist" aria-label="Choose operating system"><button role="tab" aria-selected="true" data-install="deb" class="install-tab active">Debian / Ubuntu <small>APT · amd64</small></button><button role="tab" aria-selected="false" data-install="rpm" class="install-tab">RHEL / Rocky <small>DNF · x86_64</small></button><button role="tab" aria-selected="false" data-install="opnsense" class="install-tab">OPNsense <small>FreeBSD pkg</small></button><button role="tab" aria-selected="false" data-install="freebsd" class="install-tab">FreeBSD <small>Native pkg</small></button></div>
|
||||
<div class="install-tabs" role="tablist" aria-label="Choose operating system"><button role="tab" aria-selected="true" data-install="deb" class="install-tab active">Debian / Ubuntu <small>APT · amd64</small></button><button role="tab" aria-selected="false" data-install="rpm" class="install-tab">RHEL / Rocky <small>DNF · x86_64</small></button><button role="tab" aria-selected="false" data-install="suse" class="install-tab">SUSE / openSUSE <small>Zypper · x86_64</small></button><button role="tab" aria-selected="false" data-install="opnsense" class="install-tab">OPNsense <small>FreeBSD pkg</small></button><button role="tab" aria-selected="false" data-install="freebsd" class="install-tab">FreeBSD <small>Native pkg</small></button></div>
|
||||
<div class="install-card card"><div class="install-card-head"><div><span class="section-index">TERMINAL / INSTALL</span><h2 id="install-tab-title">Debian / Ubuntu</h2><p id="install-description">Add the signed APT repository and install the server.</p></div><span class="pill" id="install-signature">GPG SIGNED</span></div><div class="code-window"><div class="code-topbar"><span><i class="tiny-dot"></i><i class="tiny-dot"></i><i class="tiny-dot"></i> <b>install.sh</b></span><button class="copy-code" id="copy-install" data-copy-target="install-command">Copy <span>↗</span></button></div><pre><code id="install-command">Preparing commands…</code></pre></div><div class="install-foot"><span id="install-note">Requires sudo privileges.</span><a id="install-reference" class="text-link" href="#">Repository files ↗</a></div></div>
|
||||
<div class="install-extra-grid single-card" id="install-extra-grid"><div class="card hint-card" id="agent-card" hidden><span class="hint-icon">01</span><h3>Docker discovery agent</h3><p>Linux also provides a separate <code>rustproxy-docker-agent</code> package. Install it separately from the main server.</p><div class="inline-command"><code id="agent-command">sudo apt install rustproxy-docker-agent</code><button data-copy-target="agent-command" class="quiet">Copy</button></div></div><div class="card hint-card"><span class="hint-icon" id="trust-index">01</span><h3>Signatures and trust</h3><p>APT and DNF repositories are GPG-signed. OPNsense and native FreeBSD currently use <code>signature_type: none</code> catalogs; use a trusted HTTPS source.</p></div></div>
|
||||
<div class="install-extra-grid single-card" id="install-extra-grid"><div class="card hint-card" id="agent-card" hidden><span class="hint-icon">01</span><h3>Docker discovery agent</h3><p>Linux also provides a separate <code>rustproxy-docker-agent</code> package. Install it separately from the main server.</p><div class="inline-command"><code id="agent-command">sudo apt install rustproxy-docker-agent</code><button data-copy-target="agent-command" class="quiet">Copy</button></div></div><div class="card hint-card"><span class="hint-icon" id="trust-index">01</span><h3>Signatures and trust</h3><p>APT, DNF and SUSE/Zypper repositories are GPG-signed. OPNsense and native FreeBSD currently use <code>signature_type: none</code> catalogs; use a trusted HTTPS source.</p></div></div>
|
||||
</section>
|
||||
|
||||
<section class="view" id="view-repository" aria-labelledby="repository-title" hidden>
|
||||
|
||||
@@ -168,7 +168,7 @@ h3{font-size:16px;font-weight:575;letter-spacing:-.3px}
|
||||
.text-link{background:none;border:0;color:var(--accent);font:11px var(--mono);padding:4px 0;white-space:nowrap}
|
||||
.text-link:hover{text-decoration:underline}
|
||||
.text-link span{margin-left:5px}
|
||||
.build-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
|
||||
.build-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px}
|
||||
.build-card,.skeleton-card{background:var(--panel);border:1px solid var(--line);padding:19px 22px 20px;min-width:0;position:relative}
|
||||
.build-card:before{content:"";position:absolute;inset:0 auto 0 0;width:2px;background:var(--green);opacity:.75}
|
||||
.build-card.off:before{background:var(--separator)}
|
||||
@@ -224,7 +224,7 @@ h3{font-size:16px;font-weight:575;letter-spacing:-.3px}
|
||||
.result-topline span:first-child{color:var(--green)}
|
||||
.catalog-bottom{display:flex;gap:15px;align-items:center;justify-content:space-between;padding:14px 19px;border-top:1px solid var(--line);color:var(--text-subtle);font:10px var(--mono)}
|
||||
.show-more{font-size:11px;padding:8px 13px}
|
||||
.install-tabs{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-bottom:16px}
|
||||
.install-tabs{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin-bottom:16px}
|
||||
.install-tab{display:flex;flex-direction:column;align-items:flex-start;gap:6px;padding:16px 18px;border:1px solid var(--line);border-bottom:2px solid var(--line);background:var(--panel);color:var(--muted);font-size:13px;font-weight:600;text-align:left;transition:border-color .14s,color .14s}
|
||||
.install-tab small{font:10px var(--mono);font-weight:400;color:var(--text-subtle)}
|
||||
.install-tab:hover{border-color:var(--border-hover);color:var(--text)}
|
||||
@@ -255,7 +255,7 @@ h3{font-size:16px;font-weight:575;letter-spacing:-.3px}
|
||||
.inline-command{display:flex;align-items:center;justify-content:space-between;gap:8px;border:1px solid var(--line);background:var(--code-bg);padding:9px 12px;margin-top:15px}
|
||||
.inline-command code{font-size:10px;overflow:auto;white-space:nowrap}
|
||||
.inline-command button{font-size:10px;padding:5px 8px}
|
||||
.endpoints-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
|
||||
.endpoints-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px}
|
||||
.endpoint-card{border:1px solid var(--line);background:var(--panel);padding:23px 22px}
|
||||
.endpoint-card-top{display:flex;align-items:center;justify-content:space-between;gap:9px;margin-bottom:19px}
|
||||
.endpoint-card h2{font-size:20px;letter-spacing:-.4px;margin:0}
|
||||
|
||||
Reference in new issue
Block a user