Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ chrome-without-the-wrapper (e.g., a custom layout that doesn't use

| Skin | Chrome feel | Notes |
| --- | --- | --- |
| `desktop` | **Vector 2022–style** | Wordmark/tagline (**`wordmarkSrc`**, **`taglineSrc`**, **`#logo` override**), **`SearchBar`** + **Search** button, username link (**`username`** + **`#username`**), user-tool cluster ( **`navTools`** preset vs **`#nav`** override ). **Main-menu glyph is icon-only** (mock). Global skin stays **desktop** until the viewport is **≤640px**; **below 1120px**, inline search collapses to a search icon; **below 768px**, watchlist hides (`nav-button-desktop` parity). |
| `desktop` | **Vector 2022–style** | Wordmark/tagline (**`wordmarkSrc`**, **`taglineSrc`**, **`#logo` override**), **`SearchBar`** + **Search** button, username link (**`username`** + **`#username`**), user-tool cluster ( **`navTools`** preset vs **`#nav`** override ). **Main-menu glyph is icon-only mock by default** — override via **`#menu`**. Global skin stays **desktop** until the viewport is **≤640px**; **below 1120px**, inline search collapses to a search icon; **below 768px**, watchlist hides (`nav-button-desktop` parity). |
| `mobile` | **Minerva-style** | Grey elevated bar: menu, Wikipedia wordmark (**`mobileWordmarkSrc`** / **`wordmarkSrc`**, **`#logo`**), search icon + notifications — **`navTools` is ignored**. |

**`ChromeFooter`** matches the skin:
Expand Down Expand Up @@ -52,6 +52,7 @@ Desktop **inline search** is always **`<SearchBar />`** inside the header (not a
| Slot | Default | Use for |
| --- | --- | --- |
| `#logo` | EN Wikipedia wordmark (+ tagline on desktop) via `<img>` | Replace with another project's wordmark / lockup |
| `#menu` | Mock burger icon (**desktop**: non-interactive glyph; **mobile**: quiet button) | Replace with an interactive main-menu trigger + popover (**`ChromeWrapper`** forwards **`#menu`**) |
| `#username` | Anchor from **`username`** (hidden when empty after trim) | Replace with custom markup before tool icons (**desktop**) |
| `#nav` | Vector-style tool icons on **desktop** only | Replace the default user-tool cluster (**`navTools` ignored**) |

Expand Down
4 changes: 2 additions & 2 deletions .agents/skills/protowiki-components/references/dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Reference prototypes:
Do not confuse:

- **`SpecialPageWrapper` `help`** — desktop title-row **Help** link (Codex docs URL)
- **`dashpage/HelpModule.vue`** — prototype-local **"Get help with editing"** sidebar/mobile card (wraps **`DashboardModule`**)
- **`template-homepage/HelpModule.vue`** — prototype-local **"Get help with editing"** sidebar/mobile card (wraps **`DashboardModule`**)

## `Dashboard`

Expand All @@ -35,7 +35,7 @@ With **`data-skin="desktop"`**, the two-column grid (`primary` ~66% + `sidebar`
Utility classes from the component stylesheet:

- **`dashboard-slot`** — min-height baseline on module roots
- **`dashboard-slot--desktop-primary`**, **`dashboard-slot--mobile-primary`**, etc. — prototype hooks for per-slot sizing (see **`template-dashboard`** / **`dashpage`**)
- **`dashboard-slot--desktop-primary`**, **`dashboard-slot--mobile-primary`**, etc. — prototype hooks for per-slot sizing (see **`template-dashboard`** / **`template-homepage`**)

### Props

Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/protowiki-getting-started/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protowiki/
│ │ ├── index.vue ← home / gallery (auto-lists prototypes)
│ │ ├── template-chrome/index.vue
│ │ ├── template-dashboard/index.vue
│ │ └── dashpage/index.vue
│ │ └── template-homepage/index.vue
│ ├── components/ ← shipped components (wrappers, primitives, article, dashboard)
│ ├── composables/ ← useSkin / useTheme (read-only hooks)
│ ├── lib/ ← theming logic, helpers
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/wiki-apis/assets/fetch_schemas.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
UA='ProtoWiki-snapshot/0.1 (https://github.com/wikimedia-research/protowiki; protowiki@wikimedia.org)'
UA='ProtoWiki-snapshot/0.1 (https://github.com/wikimedia/protowiki; protowiki@wikimedia.org)'

pretty_json() {
python3 -c 'import sys, json; json.dump(json.load(sys.stdin), sys.stdout, indent=2, sort_keys=True)'
Expand Down
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@wikimedia/codex": "^2.5.1",
"@wikimedia/codex-design-tokens": "^2.5.1",
"@wikimedia/codex-icons": "^2.5.1",
"fakewiki": "^0.0.13",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
Expand Down
62 changes: 62 additions & 0 deletions scripts/probe-dashpage-recent-changes-signals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env npx tsx
/**
* Probe language-agnostic articlequality score deltas for recent edits.
* Run: npx tsx scripts/probe-dashpage-recent-changes-signals.ts
*/

import { createDashpageRecentChangesWiki } from '../src/lib/fetchDashpageRecentChanges'
import { fetchArticleQualityScore } from '../src/lib/fetchArticleQualityScore'
import { DASHPAGE_RC_API_USER_AGENT } from '../src/lib/dashpageRecentChangesConstants'

async function sleep(ms: number): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, ms))
}

async function main(): Promise<void> {
const wiki = createDashpageRecentChangesWiki()
const deltas: number[] = []

console.log('Fetching recent changes (needs review)…')
const rc = await wiki.getRecentChanges({ limit: 12, onlyNeedsReview: true })

for (const rev of rc.revisions) {
if (!rev.id || !rev.pageName || rev.pageName.includes(':')) continue

const parentId = await wiki.getParentRevisionId(rev.pageName, rev.id)
if (parentId == null || parentId <= 0) continue

const before = await fetchArticleQualityScore(parentId, 'en', DASHPAGE_RC_API_USER_AGENT)
await sleep(300)
const after = await fetchArticleQualityScore(rev.id, 'en', DASHPAGE_RC_API_USER_AGENT)
await sleep(300)

if (before && after) {
const delta = after.score - before.score
deltas.push(delta)
console.log(
`rev ${rev.id} (${rev.pageName}): before=${before.score.toFixed(4)} after=${after.score.toFixed(4)} delta=${delta.toFixed(4)}`,
)
}
}

if (!deltas.length) {
console.log('No deltas collected — keeping default threshold 0.03')
return
}

const absDeltas = deltas.map(Math.abs).sort((a, b) => a - b)
const median = absDeltas[Math.floor(absDeltas.length / 2)] ?? 0
const p75 = absDeltas[Math.floor(absDeltas.length * 0.75)] ?? median
const suggested = Math.max(0.02, Math.min(0.05, Math.round(p75 * 100) / 100))

console.log('\nSummary:')
console.log(` samples: ${deltas.length}`)
console.log(` |delta| median: ${median.toFixed(4)}`)
console.log(` |delta| p75: ${p75.toFixed(4)}`)
console.log(` suggested display threshold (sprinthackular uses ${1e-6}): any delta > 0`)
}

main().catch((error) => {
console.error(error)
process.exit(1)
})
2 changes: 1 addition & 1 deletion scripts/snapshot-wiki-skins.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT_DIR="${1:-$ROOT/src/styles/wiki-content}"
mkdir -p "$OUT_DIR"

UA='ProtoWiki-snapshot/0.1 (https://github.com/wikimedia-research/protowiki)'
UA='ProtoWiki-snapshot/0.1 (https://github.com/wikimedia/protowiki)'

VECTOR_MODULES='site.styles|skins.vector.styles|ext.cite.styles|mediawiki.skinning.content.parsoid|mediawiki.hlist|mediawiki.ui.button|mediawiki.skinning.interface'
MINERVA_MODULES='site.styles|skins.minerva.base.styles|skins.minerva.styles|ext.cite.styles|mediawiki.skinning.content.parsoid|mediawiki.hlist|mediawiki.skinning.interface'
Expand Down
5 changes: 3 additions & 2 deletions src/components/ArticleLive.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CdxMessage, CdxProgressBar } from '@wikimedia/codex'
import ArticleRenderer from '@/components/ArticleRenderer.vue'
import ArticleWrapper from '@/components/ArticleWrapper.vue'
import type { Skin, Theme } from '@/lib/theming'
import { wipeLocalStorage } from '@/lib/wipeLocalStorage'

/** Cache of successfully fetched live article HTML (key: host + title). */
type CachedArticleBody = { html: string; liveTitle: string }
Expand All @@ -29,6 +30,7 @@ function loadFromStorage(key: string): CachedArticleBody | null {
if (!raw) return null
return JSON.parse(raw) as CachedArticleBody
} catch {
wipeLocalStorage()
return null
}
}
Expand Down Expand Up @@ -131,8 +133,7 @@ async function fetchArticle(title: string) {
})
const headers: Record<string, string> = {
Accept: 'text/html; charset=utf-8',
'Api-User-Agent':
'ProtoWiki/0.1 (https://github.com/wikimedia-research/protowiki) prototype',
'Api-User-Agent': 'ProtoWiki/0.1 (https://github.com/wikimedia/protowiki) prototype',
}
const response = await fetch(url, { headers })
if (!response.ok) {
Expand Down
33 changes: 25 additions & 8 deletions src/components/ChromeHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,12 @@ function navHas(tool: ChromeNavTool): boolean {
<!-- Vector 2022–style chrome (desktop skin) -->
<nav v-if="isDesktop" class="chrome-header__nav-desktop" aria-label="Site">
<div class="chrome-header__desktop-start">
<!-- Mock only — not interactive (FakeMediaWiki uses bare chrome / icon affordances). -->
<span class="chrome-header__menu-icon" aria-hidden="true">
<CdxIcon :icon="cdxIconMenu" />
</span>
<slot name="menu">
<!-- Mock only — not interactive (FakeMediaWiki uses bare chrome / icon affordances). -->
<span class="chrome-header__menu-icon" aria-hidden="true">
<CdxIcon :icon="cdxIconMenu" />
</span>
</slot>

<RouterLink class="chrome-header__brand-link" to="/" aria-label="Visit the main page">
<slot name="logo">
Expand Down Expand Up @@ -223,9 +225,11 @@ function navHas(tool: ChromeNavTool): boolean {

<!-- Minerva-style chrome (mobile skin) -->
<nav v-else class="chrome-header__nav-mobile" aria-label="Site">
<CdxButton weight="quiet" size="large" aria-label="Main menu">
<CdxIcon :icon="cdxIconMenu" />
</CdxButton>
<slot name="menu">
<CdxButton weight="quiet" size="large" aria-label="Main menu">
<CdxIcon :icon="cdxIconMenu" />
</CdxButton>
</slot>

<RouterLink class="chrome-header__mobile-brand" to="/" aria-label="Visit the main page">
<slot name="logo">
Expand Down Expand Up @@ -333,6 +337,15 @@ function navHas(tool: ChromeNavTool): boolean {
pointer-events: none;
}

.chrome-header[data-skin='desktop'] :slotted(.chrome-header__menu-btn) {
flex-shrink: 0;
min-width: var(--size-icon-medium, 32px);
height: var(--size-icon-medium, 32px);
margin: 0;
padding: var(--spacing-25, 4px);
padding-inline-start: var(--spacing-50, 8px);
}

.chrome-header[data-skin='desktop'] .chrome-header__menu-icon :deep(svg) {
display: block;
}
Expand Down Expand Up @@ -497,7 +510,11 @@ function navHas(tool: ChromeNavTool): boolean {
box-shadow: inset 0 -1px 3px 0 rgba(0, 0, 0, 0.08);
}

.chrome-header[data-skin='mobile'] .chrome-header__nav-mobile > .cdx-button:first-of-type {
.chrome-header[data-skin='mobile'] .chrome-header__nav-mobile > :first-child {
flex-shrink: 0;
}

.chrome-header[data-skin='mobile'] .prototype-chrome-menu-popover {
flex-shrink: 0;
}

Expand Down
10 changes: 9 additions & 1 deletion src/components/ChromeWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ interface Props {
* Forwarded to **`ChromeFooter`** when using the default **`#footer`** slot.
*/
lastEditedNotice?: boolean
/** When **`false`**, omit the default **`ChromeFooter`** (header-only chrome). */
showFooter?: boolean
/** Forwarded to **`ChromeHeader`** / **`ChromeFooter`** (Meta label; mobile footer line). */
username?: string
/** Forwarded to **`ChromeHeader`**. */
Expand All @@ -55,6 +57,7 @@ const props = withDefaults(defineProps<Props>(), {
skin: undefined,
theme: undefined,
lastEditedNotice: true,
showFooter: true,
username: undefined,
wordmarkSrc: undefined,
taglineSrc: undefined,
Expand Down Expand Up @@ -89,7 +92,11 @@ provide(PROTOWIKI_CHROME_THEME, effectiveTheme)
:tagline-src="props.taglineSrc"
:mobile-wordmark-src="props.mobileWordmarkSrc"
:nav-tools="props.navTools"
/>
>
<template v-if="$slots.menu" #menu>
<slot name="menu" />
</template>
</ChromeHeader>
</slot>

<main class="chrome-wrapper__content">
Expand All @@ -98,6 +105,7 @@ provide(PROTOWIKI_CHROME_THEME, effectiveTheme)

<slot name="footer">
<ChromeFooter
v-if="props.showFooter"
:skin="effectiveSkin"
:theme="effectiveTheme"
:last-edited-notice="props.lastEditedNotice"
Expand Down
Loading
Loading