wikipedia-pages-vue — Vue 3 port of wikipedia-pages-js

A Vite + Vue 3 (Composition API) application that is feature-identical to wikipedia-pages-js: Wikipedia pages rendered in vanilla-grid inside a vanilla-resize-box, with opaque continue-token pagination against the public MediaWiki Action API.

It exists to demonstrate that the zero-dependency vanilla-grid / vanilla-resize-box web components drop cleanly into a framework app — they are plain custom elements, so Vue treats them as native DOM and only needs thin wrapper components to bridge object props and CustomEvents.

What it shows

How vanilla-grid is loaded

The components ship as plain-JS globals that resolve their own feature scripts and CSS relative to their <script> URL, so they are not imported as ES modules. Instead:

Resizing the grid

The grid sits in a src/vanilla-resize-box/ (aria-label="Resizable Wikipedia pages grid", passed straight through the VnResizeBox.vue wrapper). Drag the corner handle to resize it — resizing is pointer-driven, with no keyboard path.

The handle carries role="separator" and takes its accessible name from the host's aria-label — here "Resizable Wikipedia pages grid — resize handle" — but is not focusable, so it adds no tab stop to the page. This app's markup needs nothing beyond the aria-label it already carries.

Differences from wikipedia-pages-js

The Wikipedia endpoint, pagination, sorting, and formatversion=2 rationale are identical to wikipedia-pages-js — see that README for the full API discussion.

Run

cd wikipedia-pages-vue
npm install
npm run dev          # Vite dev server (default http://localhost:5173)

Build

npm run build        # → wikipedia-pages-vue/dist/ (self-contained, incl. dist/vendor/)
npm run preview      # serve the production build locally
npm run typecheck    # vue-tsc (app + .vue) + tsc (vite.config.ts) — no emit

Project layout

wikipedia-pages-vue/
├── index.html                     # Vite entry — loads base+theme CSS, vendor scripts, mounts #app
├── vite.config.ts                 # isCustomElement + /vendor static-serving plugin
├── tsconfig.json                  # app config (src/**/*.ts, *.vue) — read by vue-tsc/editors by default
├── tsconfig.node.json              # Node-context config for vite.config.ts (separate lib/types)
├── public/
│   ├── styles.css                 # base app stylesheet (linked before the theme — cascade order);
│   │                               # sets overscroll-behavior-y: none (host-owed half of the grid's
│   │                               # mobile touch contract — docs/vanilla-grid/00-index.md)
│   └── themes/app-*.css           # app theme stylesheets (runtime <link> swap)
├── src/
│   ├── main.ts                    # awaits VanillaGridReady, mounts App
│   ├── App.vue                    # header, selectors, tab, detail panel, overlay
│   ├── types/
│   │   ├── global.d.ts            # triple-slash refs pulling in the 3 sibling component .d.ts files
│   │   └── wiki.ts                 # shared WikiPage row interface (data manager ↔ grid ↔ detail panel)
│   ├── components/
│   │   ├── VnGrid.vue             # <vn-grid> wrapper (events + dataManager + API)
│   │   ├── VnResizeBox.vue        # <vn-resize-box> wrapper
│   │   ├── VnGridToolbar.vue      # <vn-grid-toolbar> wrapper (v-html templates + API)
│   │   ├── PagesTab.vue           # toolbar + grid + columns + usePagesGrid wiring
│   │   ├── PageDetailPanel.vue    # detail side drawer
│   │   └── ThemeSwitchOverlay.vue # loading overlay
│   └── composables/
│       ├── useI18n.ts             # reactive i18n (port of modules/i18n.js)
│       ├── useTheme.ts            # theme switching (port of modules/theme.js)
│       ├── useWikiDataManager.ts  # WikipediaDataManager class + factory
│       └── usePagesGrid.ts        # grid lifecycle (port of pages-tab.js)