Scheduled searches with a weekly review of new and rising repositories
A search can now be saved with a schedule (every N hours, daily, or weekly at a given day and time). An internal scheduler runs it and keeps a snapshot of the results on a /data volume (JSON files, no new dependency). The new Watch tab lists the scheduled searches; the review page of each one shows, for any run of its history, the repositories never seen before and the ones that gained the most stars since the previous run. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8f4048d046
commit
02b51fed77
16 files changed
+1745
-45
No files matched your search
+114
@@ -348,8 +348,105 @@ dialog.settings {
|
||||
.seg button:hover { color: var(--text); }
|
||||
.seg button[aria-checked="true"] { background: var(--panel); color: var(--accent); box-shadow: 0 1px 3px rgba(0, 0, 0, .12); }
|
||||
|
||||
|
||||
/* ---------- Views (search / scheduled searches) ---------- */
|
||||
.views { display: inline-flex; gap: 2px; padding: 3px; background: var(--panel-2); border-radius: 10px; flex: none; }
|
||||
.views a {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
height: 30px; padding: 0 12px; border-radius: 7px;
|
||||
color: var(--muted); font-size: 13px; font-weight: 600; text-decoration: none; white-space: nowrap;
|
||||
}
|
||||
.views a:hover { color: var(--text); }
|
||||
.views a[aria-current="page"] { background: var(--panel); color: var(--accent); box-shadow: 0 1px 3px rgba(0, 0, 0, .12); }
|
||||
.views svg { width: 16px; height: 16px; }
|
||||
.pill {
|
||||
min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;
|
||||
background: var(--accent); color: #fff; font-size: 11px; font-weight: 700;
|
||||
display: inline-grid; place-items: center; font-variant-numeric: tabular-nums;
|
||||
}
|
||||
body:not([data-view="search"]) .view-search { visibility: hidden; }
|
||||
body:not([data-view="search"]) .gh-query { display: none; }
|
||||
|
||||
.view-title { margin: 0; font-size: 16px; font-weight: 650; letter-spacing: -.01em; overflow-wrap: anywhere; }
|
||||
.review-head { flex-wrap: nowrap; }
|
||||
.review-title { min-width: 0; }
|
||||
.review-head .end { flex-wrap: wrap; justify-content: flex-end; }
|
||||
.review-bar { padding-top: 0; }
|
||||
#runSel { max-width: 260px; }
|
||||
|
||||
.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
.btn.primary:hover { filter: brightness(1.08); background: var(--accent); }
|
||||
.btn.danger { color: var(--err); }
|
||||
.btn.danger:hover { background: color-mix(in srgb, var(--err) 10%, transparent); }
|
||||
|
||||
/* Saved search rows */
|
||||
.srow {
|
||||
display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 6px 18px; align-items: center;
|
||||
padding: var(--row-pad) 12px var(--row-pad) 16px; border-bottom: 1px solid var(--border); cursor: pointer;
|
||||
}
|
||||
.srow:last-child { border-bottom: 0; }
|
||||
.srow:hover { background: var(--row-hover); }
|
||||
.srow:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
||||
.srow.off { opacity: .6; }
|
||||
.srow .sname { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; font-weight: 650; }
|
||||
.srow .sq { margin-top: 2px; font: 12px var(--mono); color: var(--muted); overflow-wrap: anywhere; }
|
||||
.srow .ssched { margin-top: 4px; font-size: 12.5px; color: var(--muted); display: flex; flex-wrap: wrap; gap: 2px 14px; }
|
||||
.srow .ssched span { display: inline-flex; align-items: center; gap: 5px; }
|
||||
.srow .ssched svg { width: 14px; height: 14px; }
|
||||
.srow .sstats { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
|
||||
.srow .sacts { display: flex; gap: 2px; }
|
||||
.srow .sacts .icon-btn { width: 32px; height: 32px; }
|
||||
.srow .sacts .icon-btn svg { width: 17px; height: 17px; }
|
||||
.stat {
|
||||
display: inline-flex; align-items: center; gap: 4px; height: 24px; padding: 0 8px; border-radius: 999px;
|
||||
font-size: 12px; font-weight: 650; background: var(--panel-2); color: var(--muted); white-space: nowrap;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.stat.new { background: var(--accent-soft); color: var(--accent); }
|
||||
.stat.up { background: color-mix(in srgb, var(--ok) 14%, transparent); color: var(--ok); }
|
||||
.stat.err { background: color-mix(in srgb, var(--err) 12%, transparent); color: var(--err); }
|
||||
.stat svg { width: 12px; height: 12px; }
|
||||
.spin { animation: spin 1s linear infinite; }
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
|
||||
/* Review annotations */
|
||||
.badge.new { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); background: var(--accent-soft); }
|
||||
.meta .delta { color: var(--ok); font-weight: 650; }
|
||||
.meta .delta.down { color: var(--err); }
|
||||
.row.is-new { box-shadow: inset 3px 0 0 var(--accent); }
|
||||
.review .meta { grid-template-columns: 4.5rem 7.5rem 4.5rem 4rem 6.5rem; }
|
||||
|
||||
/* Save dialog */
|
||||
dialog.save-dlg { width: min(560px, calc(100vw - 32px)); }
|
||||
.save-body {
|
||||
display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 12px 16px; align-items: center;
|
||||
padding: 18px 22px 4px;
|
||||
}
|
||||
.text-input {
|
||||
height: 34px; padding: 0 10px; border: 1px solid var(--border); border-radius: 8px;
|
||||
background: var(--panel); font-size: 13px; outline: 0; min-width: 0;
|
||||
}
|
||||
.text-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
|
||||
#svName { width: 100%; }
|
||||
#svHours { width: 5.5rem; }
|
||||
.sched-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
||||
.hours-wrap { display: inline-flex; align-items: center; gap: 8px; }
|
||||
.query-box {
|
||||
display: block; padding: 7px 10px; border-radius: 8px; background: var(--panel-2); border: 1px solid var(--border);
|
||||
font: 12px/1.5 var(--mono); color: var(--muted); overflow-wrap: anywhere;
|
||||
}
|
||||
.check { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; }
|
||||
.check input { width: 16px; height: 16px; accent-color: var(--accent); }
|
||||
.save-hint { margin: 10px 22px 0; }
|
||||
.save-hint:empty { display: none; }
|
||||
.dlg-foot { display: flex; align-items: center; gap: 8px; padding: 16px 22px 18px; }
|
||||
.grow { flex: 1; }
|
||||
|
||||
/* ---------- Medium screens: the meta columns go under the description ---------- */
|
||||
@media (max-width: 1100px) {
|
||||
.srow { grid-template-columns: minmax(0, 1fr) auto; }
|
||||
.srow .sstats { grid-column: 1; justify-content: flex-start; }
|
||||
.srow .sacts { grid-row: 1 / span 2; grid-column: 2; }
|
||||
.row { grid-template-columns: 36px minmax(0, 1fr); grid-template-areas: "av main" "av meta" "av details"; }
|
||||
.meta { display: flex; flex-wrap: wrap; gap: 4px 16px; padding-top: 6px; }
|
||||
}
|
||||
@@ -374,6 +471,23 @@ dialog.settings {
|
||||
.status { padding: 6px 16px; }
|
||||
.gh-query { display: none; }
|
||||
dialog.settings { height: calc(100vh - 24px); width: calc(100vw - 16px); }
|
||||
.views { order: 2; margin-left: auto; }
|
||||
.views a { padding: 0 9px; }
|
||||
.views a span:not(.pill) { display: none; }
|
||||
.actions { order: 2; margin-left: 0; }
|
||||
body:not([data-view="search"]) .view-search { display: none; }
|
||||
.review-head { flex-wrap: wrap; }
|
||||
.review-title { flex: 1; }
|
||||
.review-head .end { flex: 1 1 100%; justify-content: flex-start; }
|
||||
.review-head .end .lbl { display: none; }
|
||||
#runSel { flex: 1 1 auto; max-width: none; }
|
||||
.review-bar .seg { flex: 1 1 100%; }
|
||||
.review-bar .seg button { flex: 1; padding: 0 6px; font-size: 12px; }
|
||||
.srow { padding-left: 12px; padding-right: 8px; }
|
||||
.save-body { grid-template-columns: 1fr; gap: 6px; padding: 14px 16px 4px; }
|
||||
.save-body .lbl { margin-top: 6px; }
|
||||
.save-hint { margin: 10px 16px 0; }
|
||||
.dlg-foot { padding: 14px 16px 16px; }
|
||||
.set-body { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
|
||||
.set-nav {
|
||||
display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 6px;
|
||||
|
||||
Reference in new issue
Block a user