mockups/code_search.html
Rama main · réplica de lectura del repositorio original.
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Code search — Cloudzilla</title>
<link rel="stylesheet" href="/assets/tailwind.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500&family=Geist:wght@400;500;600&display=swap" rel="stylesheet" />
</head>
<body class="min-h-screen flex flex-col antialiased font-sans">
<a href="#main-content" class="skip-link">Skip to main content</a>
<div id="cz-header"></div>
<main id="main-content" tabindex="-1" class="max-w-[1400px] mx-auto px-6 pt-6 pb-20 flex-1 w-full">
<div class="space-y-6">
<div class="rounded-lg border border-border bg-card text-card-foreground">
<div class="p-5">
<h1 class="text-2xl font-bold mb-4">Code search</h1>
<form action="code_search.html" method="GET" class="space-y-3" id="code-form">
<div class="flex gap-2">
<label for="code-search-query" class="sr-only">Search code</label>
<input id="code-search-query" type="text" name="q" placeholder="Search code..." class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 flex-1" />
<button type="submit" class="inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-4 text-sm">Search</button>
</div>
<div class="flex gap-3 text-sm">
<div class="flex items-center gap-1">
<label for="repo" class="text-muted-foreground shrink-0">Repo:</label>
<input type="text" id="repo" name="repo" placeholder="owner/repo" class="flex h-8 w-40 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-xs transition-colors placeholder:text-muted-foreground" />
</div>
<div class="flex items-center gap-1">
<label for="lang" class="text-muted-foreground shrink-0">Language:</label>
<input type="text" id="lang" name="lang" placeholder="go, py, js..." class="flex h-8 w-28 rounded-md border border-input bg-transparent px-2 py-1 text-xs shadow-xs transition-colors placeholder:text-muted-foreground" />
</div>
</div>
</form>
</div>
</div>
<div id="code-results" class="space-y-6"></div>
</div>
</main>
<div id="cz-footer"></div>
<script src="shell.js"></script>
<script>
(function () {
// snippet is ts_headline output: the matched term wrapped in ** **, shown verbatim inside <pre> like the real page.
var HITS = [
{ owner: 'mkappworks', repo: 'cloudzilla', path: 'internal/router/router.go', rank: 0.607,
snippet: 'func New(h *handler.Handlers, mw *middleware.Set) http.Handler {\n\tr := chi.New**Router**()\n\tr.Use(mw.RequestID, mw.Logger)\n\tr.With(optAuthMW).Get("/search", h.PageSearch)' },
{ owner: 'mkappworks', repo: 'cloudzilla', path: 'internal/router/router_test.go', rank: 0.486,
snippet: 'func newVerification**Router**(t *testing.T) http.Handler {\n\tt.Helper()\n\tdb := testutil.OpenDB(t)\n\treturn router.New(handlers(db), middlewares(db))' },
{ owner: 'acme-corp', repo: 'oauth-proxy', path: 'cmd/proxy/main.go', rank: 0.412,
snippet: 'mux := http.NewServeMux()\n\t**Router** := newRoutes(cfg, sessions)\n\tmux.Handle("/", **Router**)\n\tlog.Fatal(http.ListenAndServe(cfg.Addr, mux))' },
{ owner: 'stitch-labs', repo: 'htmx-kit', path: 'src/router.ts', rank: 0.391,
snippet: 'export class **Router** {\n private routes: Route[] = [];\n add(path: string, view: View) {\n this.routes.push({ path, view });' },
{ owner: 'openforge', repo: 'runner', path: 'api/server.py', rank: 0.288,
snippet: 'from fastapi import API**Router**\n\n**Router** = API**Router**(prefix="/jobs")\n\n@**Router**.post("/")\nasync def enqueue(job: Job):' },
{ owner: 'mkappworks', repo: 'go-service-starter', path: 'internal/http/router.go', rank: 0.254,
snippet: '// **Router** wires the middleware stack and mounts every handler group.\nfunc **Router**(app *App) http.Handler {\n\tr := chi.NewMux()' }
];
function esc(s) { var d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
function toks(q) { return q.toLowerCase().split(/\s+/).filter(Boolean); }
function plain(s) { return s.replace(/\*\*/g, ''); }
// Re-marks the snippet for a query other than the sample one, as ts_headline would.
function mark(s, q) {
var t = toks(q).map(function (x) { return x.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); });
return plain(s).replace(new RegExp('(' + t.join('|') + ')', 'gi'), '**$1**');
}
function extOf(path) { return path.split('.').pop().toLowerCase(); }
var input = document.getElementById('code-search-query');
var repoIn = document.getElementById('repo');
var langIn = document.getElementById('lang');
function render(q, repo, lang) {
var out = document.getElementById('code-results');
document.title = (q ? 'Code search: ' + q : 'Code search') + ' — Cloudzilla';
if (!q) {
out.innerHTML = '<div class="rounded-md border border-border bg-card p-12 text-center"><p class="text-muted-foreground">Enter a search query above to search code across all repositories you can read.</p></div>';
return;
}
var t = toks(q);
var hits = HITS.filter(function (h) {
var hay = (plain(h.snippet) + ' ' + h.path).toLowerCase();
return t.every(function (x) { return hay.indexOf(x) >= 0; }) &&
(!repo || (h.owner + '/' + h.repo).toLowerCase() === repo.toLowerCase()) &&
(!lang || extOf(h.path) === lang.toLowerCase().replace(/^\./, ''));
});
if (!hits.length) {
out.innerHTML = '<div class="bg-background border border-border rounded-lg p-8 text-center"><p class="text-muted-foreground">No code results found for ' + esc(q) + '.</p>' +
'<p class="text-sm text-muted-foreground mt-2">Files are indexed after each push. Empty or binary-only repos will return no results.</p></div>';
return;
}
var summary = hits.length + ' ' + (hits.length === 1 ? 'result' : 'results') + ' matching "' + q + '"' +
(repo ? ' in ' + repo : '') + (lang ? ' (' + lang + ')' : '');
out.innerHTML = '<p class="text-sm text-muted-foreground px-1">' + esc(summary) + '</p>' +
'<div class="rounded-md border border-border bg-card divide-y divide-border">' + hits.map(function (h) {
var snippet = q.toLowerCase() === 'router' ? h.snippet : mark(h.snippet, q);
return '<div class="px-6 py-4"><div class="flex items-start justify-between gap-4 mb-1">' +
'<a href="blob.html" class="text-foreground font-medium hover:underline text-sm font-mono">' + esc(h.owner + '/' + h.repo + '/' + h.path) + '</a></div>' +
'<pre class="text-xs text-foreground bg-muted rounded-sm p-2 overflow-x-auto whitespace-pre-wrap">' + esc(snippet) + '</pre></div>';
}).join('') + '</div>';
}
function go(q, repo, lang, push) {
input.value = q;
repoIn.value = repo;
langIn.value = lang;
if (push) {
var p = new URLSearchParams({ q: q });
if (repo) p.set('repo', repo);
if (lang) p.set('lang', lang);
history.pushState(null, '', 'code_search.html?' + p.toString());
}
render(q, repo, lang);
}
function fromLocation() {
var p = new URLSearchParams(location.search);
go((p.get('q') || '').trim(), (p.get('repo') || '').trim(), (p.get('lang') || '').trim(), false);
}
document.getElementById('code-form').addEventListener('submit', function (e) {
e.preventDefault();
go(input.value.trim(), repoIn.value.trim(), langIn.value.trim(), true);
});
window.addEventListener('popstate', fromLocation);
fromLocation();
})();
</script>
</body>
</html>