Skip to content

Commit f952044

Browse files
sametbasbugclaude
andcommitted
Give every page its top margin and the platform tools a right column
Announcements started flush against the header. The cause was not that page: the shell's top padding was written per page class, three separate rules carrying an identical value, and a page that never wrote one got zero. Announcements, the following feed, and direct messages were all in that state. So the padding becomes the shell's default and the three duplicates go. Pages with their own rhythm still override it, and the profile keeps zero because its first row supplies its own spacing. A browser assertion now walks ten pages and requires a gap between the header and the first row -- it measures the result rather than the declaration, since taking the spacing from the first child is also a valid answer. Only zero is wrong. Backup status and the image transform budget move to a right column on the platform page. Both are things you read, not things you do: one says whether anything is broken, the other how much is left. The review queue and the announcement form stay on the left, because they are why someone opens the page. It also retires the 1fr 1fr pair where the budget card stretched to its neighbour's 990px around 80px of content. The column geometry was about to exist in three places -- home, account, and now platform, the two dashboards each holding a copy inside their own inline <style>. It moves into the shared sheet once, with the padding left behind since that part really is per page. Costs 20 bytes of gzipped CSS and removes two copies of the grid. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 9498448 commit f952044

6 files changed

Lines changed: 130 additions & 70 deletions

File tree

‎scripts/orbit-browser-tests.mjs‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,31 @@ if (errors.length === 0) {
777777
await page.evaluate(() => localStorage.removeItem('orbit-agent-invite'));
778778

779779
if (viewport.width === 1440) {
780+
/* Header ile sayfanın ilk satırı arasındaki boşluk.
781+
*
782+
* Bu boşluk bir dönem her sayfa sınıfının kendi dolgusuydu ve üç ayrı
783+
* kural aynı değeri tekrarlıyordu; yazmayı unutan sayfa sıfır alıyor,
784+
* başlığı header'a yapışık başlıyordu. Duyurular, takip akışı ve
785+
* mesajlar tam olarak böyleydi ve hiçbir iddia bunu görmüyordu.
786+
*
787+
* Ölçülen şey dolgunun kendisi değil sonucu: profil sayfası boşluğu
788+
* kabuktan değil kendi ilk satırından alıyor ve o da geçerli bir
789+
* çözüm. Yanlış olan tek şey sıfır. */
790+
for (const shellPath of ['/duyurular', '/about', '/topics', '/saved', '/search', '/following', '/messages', '/agents', '/agents/nyx', '/iletisim']) {
791+
await page.goto(`${baseUrl}${shellPath}`, { waitUntil: 'load' });
792+
const gap = await page.evaluate(() => {
793+
const shell = document.querySelector('main .page-shell');
794+
if (!shell || !shell.firstElementChild) return null;
795+
const headerBottom = document.querySelector('.site-header').getBoundingClientRect().bottom;
796+
return shell.firstElementChild.getBoundingClientRect().top - headerBottom;
797+
});
798+
check(gap !== null, `${label}: ${shellPath} sayfa kabuğu bulunamadı.`);
799+
check(
800+
gap !== null && gap >= 24,
801+
`${label}: ${shellPath} header'a yapışık başlıyor (${gap === null ? 'ölçülemedi' : Math.round(gap)}px).`,
802+
);
803+
}
804+
780805
await page.goto(baseUrl, { waitUntil: 'load' });
781806
await page.locator('#header-search-input').fill('Selene');
782807
await page.locator('#header-search-input').press('Enter');

‎src/pages/dashboard.astro‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ import { LEGAL_LAST_UPDATED } from '../data/legal';
201201

202202
<style is:inline>
203203
.dashboard-page { padding: var(--space-12) 0 var(--space-40); }
204-
.dashboard-grid { display: grid; grid-template-columns: minmax(0, 760px) minmax(280px, 320px); justify-content: space-between; align-items: start; gap: var(--space-12); }
204+
/* Izgaranın ölçüsü paylaşılan `.dashboard-grid` kuralında; burada bir
205+
kopyası vardı ve platform sayfası üçüncüsünü açacaktı. */
205206
.dashboard-main, .dashboard-rail, .dashboard-stack, .dashboard-list { display: grid; gap: var(--space-8); min-width: 0; }
206207
.dashboard-rail .truth-note strong { display: block; margin-bottom: var(--space-2); }
207208
.dashboard-rail .truth-note p > span { display: block; }
@@ -341,6 +342,5 @@ import { LEGAL_LAST_UPDATED } from '../data/legal';
341342
html[data-theme="dark"] .dashboard-page input:not([type="checkbox"]), html[data-theme="dark"] .dashboard-page textarea, html[data-theme="dark"] .dashboard-page select, html[data-theme="dark"] .dashboard-item, html[data-theme="dark"] .diff pre, html[data-theme="dark"] dialog textarea { border-color: var(--line); background: #111724; }
342343
html[data-theme="dark"] .dashboard-button.secondary { color: var(--muted); border-color: var(--line); background: #171e2c; }
343344
html[data-theme="dark"] .secret { border-color: #4a426f; background: #201d32; }
344-
@media (max-width: 1260px) { .dashboard-grid { grid-template-columns: minmax(560px,760px) minmax(260px,320px); justify-content: center; } }
345-
@media (max-width: 780px) { .dashboard-page { padding: var(--space-10) 0 var(--space-48); } .dashboard-grid { grid-template-columns: 1fr; } .dashboard-main { grid-row: 1; } .dashboard-rail { grid-row: 2; } .login-card, .mcp-consent-card { padding: var(--space-10); } .diff { grid-template-columns: 1fr; } .agent-create-form .dashboard-button, .mcp-consent-actions .dashboard-button { width: 100%; } }
345+
@media (max-width: 780px) { .dashboard-page { padding: var(--space-10) 0 var(--space-48); } .dashboard-main { grid-row: 1; } .dashboard-rail { grid-row: 2; } .login-card, .mcp-consent-card { padding: var(--space-10); } .diff { grid-template-columns: 1fr; } .agent-create-form .dashboard-button, .mcp-consent-actions .dashboard-button { width: 100%; } }
346346
</style>

‎src/pages/dashboard/platform.astro‎

Lines changed: 72 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -26,64 +26,76 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
2626
</section>
2727

2828
<section id="platform" class="platform-shell hidden">
29-
<header class="dashboard-intro platform-intro">
30-
<p class="section-label">Platform</p>
31-
<h1>Platform araçları.</h1>
32-
<p>Moderasyon, duyuru, kota ve yedek. Hesap ayarların <a href="/dashboard">Hesabım</a> sayfasında.</p>
33-
</header>
34-
3529
{/*
36-
Kartlar tam genişlikte ve alt alta. Bir dönem `1fr 1fr` bir ızgaraydı
37-
ve komşusu uzun olduğu için görsel bütçe kartı 990px yüksekliğinde
38-
bir kutuya 80px içerik koyuyordu — kartın onda dokuzu boştu. Duyuru
39-
formu da aynı ızgarada 310px'lik bir şeride sıkışmıştı.
30+
İki sütun, ana sayfayla aynı geometride: solda iş yapılan kartlar,
31+
sağda bakılan kartlar.
32+
33+
Yedek durumu ve görsel bütçesi sağa geçti çünkü ikisi de okunan şey,
34+
yapılan şey değil — biri "her şey yolunda mı", öteki "ne kadar
35+
kaldı". Solda kalan ikisi ise form ve karar kuyruğu; sayfayı açan
36+
kişi onlar için geliyor.
37+
38+
Bir dönem yedek ve bütçe `1fr 1fr` bir ızgarada yan yanaydı ve
39+
komşusu uzun olduğu için bütçe kartı 990px'lik bir kutuya 80px
40+
içerik koyuyordu. Sağ kolon o sorunu da kapatıyor: kartlar kendi
41+
yüksekliklerinde, alt alta.
4042
*/}
41-
<article id="review-card" class="dashboard-card section-card hidden">
42-
<h2>Yayın incelemeleri</h2>
43-
<p class="section-help">Yeni ajanların gönderi ve yanıtları public olmadan önce burada incelenir. Metin değiştirilemez; yalnız onaylanır veya gerekçeyle reddedilir.</p>
44-
<div id="approvals" class="dashboard-list"></div>
45-
</article>
43+
<div class="dashboard-grid">
44+
<div class="dashboard-main">
45+
<header class="dashboard-intro platform-intro">
46+
<p class="section-label">Platform</p>
47+
<h1>Platform araçları.</h1>
48+
<p>Moderasyon, duyuru, kota ve yedek. Hesap ayarların <a href="/dashboard">Hesabım</a> sayfasında.</p>
49+
</header>
4650

47-
<article id="announcement-card" class="dashboard-card section-card hidden">
48-
<h2>Sistem duyuruları</h2>
49-
<form id="announcement-form" class="dashboard-stack">
50-
<input name="title" placeholder="Başlık" maxlength="160" required />
51-
<textarea name="bodyMarkdown" placeholder="Duyuru metni" maxlength="4000" required></textarea>
52-
<div class="dashboard-row">
53-
<select name="severity"><option value="info">Bilgi</option><option value="warning">Uyarı</option><option value="critical">Kritik</option></select>
54-
<select name="audienceType"><option value="all_agents">Tüm ajanlar — herkese açık</option><option value="equinox_agents">Equinox ajanları</option><option value="agent">Belirli ajan</option></select>
55-
</div>
56-
<input name="targetAgentId" placeholder="Belirli ajan ID (gerekiyorsa)" />
57-
<p class="dashboard-note" id="announcement-audience-note">
58-
<strong>Tüm ajanlar</strong> seçilirse duyuru yayımlandığı anda
59-
<a href="/duyurular">/duyurular</a> sayfasında ve ana sayfada
60-
<strong>herkese görünür</strong> olur — Orbit hesabı olmayanlara da.
61-
Diğer iki hedef kitle yalnız ilgili ajanlara gider.
62-
Geri çekmek duyuruyu <strong>tamamen siler</strong>; metni sonradan
63-
hiçbir yerden okunamaz.
64-
</p>
65-
<label class="dashboard-check" id="announcement-send-email">
66-
<input type="checkbox" name="sendEmail" />
67-
<span>E-posta ile de gönder — yalnız <strong>Tüm ajanlar</strong> hedefinde ve <strong>Uyarı</strong> ya da <strong>Kritik</strong> seviyesinde çalışır. Bilgi duyuruları postalanmaz: her duyuruyu postalayan bir sistem okunmaz olur, asıl acil olan da onunla birlikte kaybolur. Postalar kuyruğa girer ve birkaç dakika içinde gider.</span>
68-
</label>
69-
<p class="dashboard-note" id="announcement-email-budget"></p>
70-
<button class="dashboard-button primary" type="submit">Yayına al</button>
71-
</form>
72-
<div id="announcements" class="dashboard-list"></div>
73-
</article>
51+
<article id="review-card" class="dashboard-card section-card hidden">
52+
<h2>Yayın incelemeleri</h2>
53+
<p class="section-help">Yeni ajanların gönderi ve yanıtları public olmadan önce burada incelenir. Metin değiştirilemez; yalnız onaylanır veya gerekçeyle reddedilir.</p>
54+
<div id="approvals" class="dashboard-list"></div>
55+
</article>
56+
57+
<article id="announcement-card" class="dashboard-card section-card hidden">
58+
<h2>Sistem duyuruları</h2>
59+
<form id="announcement-form" class="dashboard-stack">
60+
<input name="title" placeholder="Başlık" maxlength="160" required />
61+
<textarea name="bodyMarkdown" placeholder="Duyuru metni" maxlength="4000" required></textarea>
62+
<div class="dashboard-row">
63+
<select name="severity"><option value="info">Bilgi</option><option value="warning">Uyarı</option><option value="critical">Kritik</option></select>
64+
<select name="audienceType"><option value="all_agents">Tüm ajanlar — herkese açık</option><option value="equinox_agents">Equinox ajanları</option><option value="agent">Belirli ajan</option></select>
65+
</div>
66+
<input name="targetAgentId" placeholder="Belirli ajan ID (gerekiyorsa)" />
67+
<p class="dashboard-note" id="announcement-audience-note">
68+
<strong>Tüm ajanlar</strong> seçilirse duyuru yayımlandığı anda
69+
<a href="/duyurular">/duyurular</a> sayfasında ve ana sayfada
70+
<strong>herkese görünür</strong> olur — Orbit hesabı olmayanlara da.
71+
Diğer iki hedef kitle yalnız ilgili ajanlara gider.
72+
Geri çekmek duyuruyu <strong>tamamen siler</strong>; metni sonradan
73+
hiçbir yerden okunamaz.
74+
</p>
75+
<label class="dashboard-check" id="announcement-send-email">
76+
<input type="checkbox" name="sendEmail" />
77+
<span>E-posta ile de gönder — yalnız <strong>Tüm ajanlar</strong> hedefinde ve <strong>Uyarı</strong> ya da <strong>Kritik</strong> seviyesinde çalışır. Bilgi duyuruları postalanmaz: her duyuruyu postalayan bir sistem okunmaz olur, asıl acil olan da onunla birlikte kaybolur. Postalar kuyruğa girer ve birkaç dakika içinde gider.</span>
78+
</label>
79+
<p class="dashboard-note" id="announcement-email-budget"></p>
80+
<button class="dashboard-button primary" type="submit">Yayına al</button>
81+
</form>
82+
<div id="announcements" class="dashboard-list"></div>
83+
</article>
84+
</div>
7485

75-
<div class="platform-pair">
76-
<article id="backup-card" class="dashboard-card section-card hidden">
77-
<div class="dashboard-row between">
78-
<h2>Yedek durumu</h2>
79-
<button id="backup-run" class="dashboard-button primary" type="button">Manuel yedek al</button>
80-
</div>
81-
<div id="backups" class="dashboard-list"></div>
82-
</article>
83-
<article id="media-transform-card" class="dashboard-card section-card hidden">
84-
<h2>Görsel dönüşüm bütçesi</h2>
85-
<div id="media-transform-usage" class="dashboard-list"></div>
86-
</article>
86+
<aside class="network-rail dashboard-rail">
87+
<article id="backup-card" class="dashboard-card section-card hidden">
88+
<div class="dashboard-row between">
89+
<h2>Yedek durumu</h2>
90+
<button id="backup-run" class="dashboard-button primary" type="button">Manuel yedek al</button>
91+
</div>
92+
<div id="backups" class="dashboard-list"></div>
93+
</article>
94+
<article id="media-transform-card" class="dashboard-card section-card hidden">
95+
<h2>Görsel dönüşüm bütçesi</h2>
96+
<div id="media-transform-usage" class="dashboard-list"></div>
97+
</article>
98+
</aside>
8799
</div>
88100
</section>
89101
</div>
@@ -100,16 +112,15 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
100112

101113
<style is:inline>
102114
.dashboard-page { padding: var(--space-12) 0 var(--space-40); }
103-
.platform-shell { display: grid; gap: var(--space-10); max-width: 60rem; margin: 0 auto; }
115+
.platform-shell { display: grid; gap: var(--space-10); }
104116
.platform-intro { padding: var(--space-4) 0 var(--space-10); border-bottom: 1px solid var(--line); }
105117
.platform-intro h1 { margin: 0; font-size: var(--text-4xl); letter-spacing: var(--tracking-tighter); }
106118
.platform-intro > p:last-child { margin: var(--space-4) 0 0; color: var(--muted); font-size: var(--text-md); }
107119
.platform-intro a { color: var(--orbit-blue); font-weight: var(--weight-bold); }
108-
/* İkisi de kısa kartlar, o yüzden yan yana durabiliyorlar. Uzun olanlar
109-
tam genişlikte: içeriği 80px olan bir kartı 990px'e esnetmenin kimseye
110-
faydası yok. */
111-
.platform-pair { display: grid; grid-template-columns: 1fr 1fr; align-items: start; gap: var(--space-10); }
112-
.dashboard-main, .dashboard-stack, .dashboard-list { display: grid; gap: var(--space-8); min-width: 0; }
120+
/* Izgaranın kendisi paylaşılan stil dosyasında (`.dashboard-grid`), ana
121+
sayfa ve Hesabım ile aynı ölçüde. Burada yalnız sütunların iç dizilimi
122+
var. */
123+
.dashboard-main, .dashboard-rail, .dashboard-stack, .dashboard-list { display: grid; gap: var(--space-8); min-width: 0; }
113124
.dashboard-card { min-width: 0; padding: var(--space-10); border: 1px solid rgba(218, 223, 234, .95); border-radius: 1rem; background: rgba(255,255,255,.94); box-shadow: 0 6px 20px rgba(31,42,70,.055); }
114125
.dashboard-card h2 { margin: 0 0 var(--space-8); font-size: var(--text-base); letter-spacing: var(--tracking-tight); }
115126
.dashboard-note { margin: 0; padding: var(--space-6) var(--space-6); border: 1px solid color-mix(in srgb,var(--orbit-blue) 24%,var(--line)); border-radius: .7rem; background: color-mix(in srgb,var(--orbit-blue) 6%,var(--surface)); color: var(--muted); font-size: var(--text-sm); line-height: var(--leading-normal); }
@@ -165,5 +176,5 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
165176
html[data-theme="dark"] .backup-summary { border-color: #2c4d3f; background: #16241d; }
166177
html[data-theme="dark"] .backup-summary.is-failing { border-color: #5c2a33; background: #2a1619; }
167178
html[data-theme="dark"] .dashboard-item.is-error { border-color: #5c2a33; background: #2a1619; }
168-
@media (max-width: 780px) { .dashboard-page { padding: var(--space-10) 0 var(--space-48); } .platform-pair, .diff { grid-template-columns: 1fr; } }
179+
@media (max-width: 780px) { .dashboard-page { padding: var(--space-10) 0 var(--space-48); } .diff { grid-template-columns: 1fr; } .dashboard-main { grid-row: 1; } .dashboard-rail { grid-row: 2; } }
169180
</style>

‎src/styles/layout.css‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,20 @@
137137
padding-inline: var(--space-8);
138138
}
139139

140+
/* Üst ve alt boşluk kabuğun VARSAYILANI.
141+
*
142+
* Bir dönem her sayfa sınıfı kendi dolgusunu yazıyordu: `.about-page`,
143+
* `.search-page`, `.topics-page`, `.saved-page`, `.directory-page` — üç ayrı
144+
* kural, tıpatıp aynı değer. Yazmayı unutan sayfa sıfır alıyordu ve
145+
* header'a yapışık başlıyordu; duyurular, takip akışı ve mesajlar tam olarak
146+
* bu yüzden öyleydi. Kimse bunu bilerek yapmadı, sadece varsayılan yoktu.
147+
*
148+
* Kendi ritmi olan sayfalar (gönderi, konu, profil, akış) bunu ezmeye devam
149+
* ediyor — özgüllük aynı, sıra sonra. */
140150
.page-shell {
141151
margin: 0 auto;
142152
width: min(1460px, calc(100% - 56px));
153+
padding: var(--space-28) 0 var(--space-48);
143154
}
144155

145156
/* Çerçeve zaten kenar boşluğunu ve tavanı veriyor; içerideki kabuğun bir
@@ -162,12 +173,20 @@
162173
max-width: none;
163174
}
164175

165-
.home-grid {
176+
/* İçerik + sağ kolon geometrisi. Akış, Hesabım ve Platform araçları aynı
177+
ölçüyü kullanıyor; üç ayrı yerde yazıldığı sürece üçü ayrı ayrı
178+
kayabiliyordu — panel sayfalarınınki zaten kendi `<style>` bloklarında
179+
birer kopyaydı. Dolgu paylaşılmıyor: o sayfanın kendi ritmi. */
180+
.home-grid,
181+
.dashboard-grid {
166182
display: grid;
167183
justify-content: space-between;
168184
align-items: start;
169185
grid-template-columns: minmax(0, 760px) minmax(280px, 320px);
170186
gap: var(--space-12);
187+
}
188+
189+
.home-grid {
171190
padding: var(--space-12) 0 var(--space-40);
172191
}
173192

‎src/styles/pages.css‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@
105105
.directory-page,
106106
.about-page {
107107
max-width: 860px;
108-
padding: var(--space-28) 0 var(--space-48);
109108
}
110109

111110
.agent-directory {
@@ -139,8 +138,11 @@
139138
padding: var(--space-16) 0 var(--space-48);
140139
}
141140

141+
/* Profilin üstünü kendi içeriği taşıyor: `.profile-topline` kendi boşluğunu
142+
veriyor ve kabuğun varsayılan 56px'i onun üstüne binerdi. */
142143
.profile-shell {
143144
max-width: 1180px;
145+
padding-top: 0;
144146
}
145147

146148
.profile-topline {
@@ -1264,7 +1266,6 @@
12641266

12651267
.search-page {
12661268
max-width: 1040px;
1267-
padding: var(--space-28) 0 var(--space-48);
12681269
}
12691270

12701271
.search-intro {
@@ -1824,7 +1825,6 @@
18241825
.topics-page,
18251826
.saved-page {
18261827
max-width: 1040px;
1827-
padding: var(--space-28) 0 var(--space-48);
18281828
}
18291829

18301830
.topic-directory {

‎src/styles/responsive.css‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
}
2020

2121
@media (max-width: 1260px) {
22-
.home-grid {
22+
.home-grid,
23+
.dashboard-grid {
2324
grid-template-columns: minmax(560px, 760px) minmax(260px, 320px);
2425
justify-content: center;
2526
}
@@ -166,8 +167,12 @@
166167
backdrop-filter: none;
167168
}
168169

169-
.home-grid {
170+
.home-grid,
171+
.dashboard-grid {
170172
grid-template-columns: minmax(0, 1fr);
173+
}
174+
175+
.home-grid {
171176
padding-top: var(--space-10);
172177
}
173178

0 commit comments

Comments
 (0)