Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0f043e5
feat(component-library): let provideFutureFlags take refs and getters
arnoldstoba Oct 5, 2026
da546cf
feat(component-library): add the mt-app application shell with MtCont…
arnoldstoba Oct 5, 2026
16bc2a2
update snapshots
arnoldstoba Oct 5, 2026
22b0e5e
feat(component-library): add the drawer's modal layer without changin…
arnoldstoba Oct 6, 2026
487b62c
chore(component-library): merge the app shell silently without docs, …
arnoldstoba Oct 8, 2026
921b011
refactor(component-library): name the app shell regions and simplify …
arnoldstoba Oct 8, 2026
8a8b9ae
test(component-library): remove duplicated app shell tests and tidy t…
arnoldstoba Oct 8, 2026
88a991c
feat(component-library): hide app shell regions per route and add an …
arnoldstoba Oct 8, 2026
6e2d59f
refactor(component-library): make the drawer internal
arnoldstoba Oct 8, 2026
66c8389
chore(component-library): limit the changesets to consumer-facing cha…
arnoldstoba Oct 8, 2026
3dc2b13
fix(component-library): use a sizing token for the loading bar
arnoldstoba Oct 8, 2026
51f33bf
refactor(playground-admin): turn the playground into a production-lik…
arnoldstoba Oct 8, 2026
d9f892f
fix(playground-admin): restore the sidebar frame
arnoldstoba Oct 8, 2026
388d45a
feat(component-library): frame the app shell sidebar in the desktop l…
arnoldstoba Oct 8, 2026
64d11ec
fix(playground-admin): use 8px inline padding in the header
arnoldstoba Oct 8, 2026
72ac26b
chore(component-library): name every component that the reka-ui updat…
arnoldstoba Oct 8, 2026
df25bdd
chore(component-library): reword the reka-ui changeset
arnoldstoba Oct 8, 2026
ec330f7
refactor(playground-admin): drop the header and use a full-width CMS …
arnoldstoba Oct 8, 2026
acbf34e
chore(component-library): raise the MtButton size budget after rebasi…
arnoldstoba Oct 12, 2026
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
5 changes: 5 additions & 0 deletions .changeset/escape-closes-innermost-overlay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shopware-ag/meteor-component-library": patch
---

`mt-select` and `mt-tooltip` now call `preventDefault()` on the Escape `keydown` event when Escape closes their result list or tooltip. Your own Escape handlers can check `event.defaultPrevented` to leave that press alone, so one press doesn't also close a surrounding dialog.
5 changes: 5 additions & 0 deletions .changeset/update-reka-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shopware-ag/meteor-component-library": patch
---

Update `reka-ui` from `^2.6.0` to `^2.10.5`. The components built on it now use this version: `MtDropdownMenuRoot`, `MtDropdownMenuPortal`, `MtDropdownMenuTrigger`, `MtDropdownMenuSub`, `MtActionMenu`, the collapsed items menu of `MtBreadcrumb` and `MtCollapsible`.
2 changes: 2 additions & 0 deletions examples/playground-admin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
34 changes: 34 additions & 0 deletions examples/playground-admin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Playground: admin

A minimal Vue 3 + Vite + TypeScript application built on the `<mt-app>` application shell, set up the way a
production app would use it:

- navigation and sidebar, which become drawers on small screens;
- lazy-loaded routes with a page title each, which the shell announces to screen readers, plus the
optional loading bar;
- a full-screen route that hides the shell's regions with `meta.mtAppRegions`;
- a not-found page, the theme and language settings, a confirmation modal and a snackbar.

The app consumes the component library from its sources, so library changes show up immediately and no
library build is needed.

```sh
pnpm --filter playground-admin dev # http://localhost:3002
pnpm --filter playground-admin lint:types # type check (uses the library's built types)
```

## Structure

The app follows the [`create-vue`](https://github.com/vuejs/create-vue) layout, and the names follow the
[Vue style guide](https://vuejs.org/style-guide/).

```
src/
components/
AppNav.vue the navigation
AppSidebar.vue the sidebar
views/ one view per route
router/ routes and page titles
i18n/ translations and the remembered language
assets/main.css the shared page layout
```
1 change: 1 addition & 0 deletions examples/playground-admin/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
12 changes: 12 additions & 0 deletions examples/playground-admin/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Meteor playground</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
28 changes: 28 additions & 0 deletions examples/playground-admin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "playground-admin",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint:types": "vue-tsc --build"
},
"dependencies": {
"@shopware-ag/meteor-component-library": "workspace:*",
"vue": "^3.5.13",
"vue-i18n": "^11.4.5",
"vue-router": "^5.1.0"
},
"devDependencies": {
"@shopware-ag/meteor-icon-kit": "workspace:*",
"@types/node": "^22.10.0",
"@vitejs/plugin-vue": "^6.0.7",
"@vue/tsconfig": "^0.9.1",
"typescript": "~5.9.3",
"vite": "^8.0.0",
"vite-plugin-svgstring": "^1.0.0",
"vue-tsc": "^3.2.0"
}
}
29 changes: 29 additions & 0 deletions examples/playground-admin/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { RouterView } from "vue-router";
import { MtApp } from "@shopware-ag/meteor-component-library";
import AppNav from "./components/AppNav.vue";
import AppSidebar from "./components/AppSidebar.vue";

const { t } = useI18n();
</script>

<template>
<mt-app
:navigation-label="t('nav.label')"
:sidebar-label="t('sidebar.label')"
loading-bar
>
<template #navigation>
<AppNav />
</template>

<template #content>
<RouterView />
</template>

<template #sidebar>
<AppSidebar />
</template>
</mt-app>
</template>
18 changes: 18 additions & 0 deletions examples/playground-admin/src/assets/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* The padding of every page. */
.page {
padding: var(--scale-size-32);
}

/* Stacks its children with the default spacing. */
.stack {
display: grid;
gap: var(--scale-size-16);
align-content: start;
}

/* A row of buttons at the end of a footer. */
.actions {
display: flex;
justify-content: flex-end;
gap: var(--scale-size-8);
}
55 changes: 55 additions & 0 deletions examples/playground-admin/src/components/AppNav.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { MtLink, MtUser } from "@shopware-ag/meteor-component-library";

const { t } = useI18n();

const routes = [
{ to: "/", label: "nav.dashboard" },
{ to: "/cms", label: "nav.cms" },
{ to: "/settings", label: "nav.settings" },
];
</script>

<template>
<div class="app-nav">
<ul class="app-nav__links">
<li v-for="route in routes" :key="route.to">
<mt-link class="app-nav__link" :to="route.to">{{
t(route.label)
}}</mt-link>
</li>
</ul>

<div class="app-nav__footer">
<mt-user name="Mila Hoffmann" subtitle="mila.hoffmann@example.com" />
</div>
</div>
</template>

<style scoped>
.app-nav {
display: flex;
flex: 1;
flex-direction: column;
width: 15rem;
padding: var(--scale-size-16);
}

.app-nav__links {
display: grid;
gap: var(--scale-size-8);
margin: 0;
padding: 0;
list-style: none;
}

.app-nav__footer {
margin-block-start: auto;
padding-block-start: var(--scale-size-16);
}

.app-nav__link.router-link-exact-active {
font-weight: var(--font-weight-semibold);
}
</style>
21 changes: 21 additions & 0 deletions examples/playground-admin/src/components/AppSidebar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { MtText } from "@shopware-ag/meteor-component-library";

const { t } = useI18n();
</script>

<template>
<div class="app-sidebar">
<mt-text size="xs" color="color-text-secondary-default">{{
t("sidebar.label")
}}</mt-text>
</div>
</template>

<style scoped>
.app-sidebar {
width: 20rem;
padding: var(--scale-size-16);
}
</style>
40 changes: 40 additions & 0 deletions examples/playground-admin/src/i18n/de.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { Messages } from "./en";

export const de: Messages = {
app: {
title: "Meteor Playground",
},
nav: {
label: "Hauptnavigation",
dashboard: "Dashboard",
cms: "CMS",
settings: "Einstellungen",
},
sidebar: {
label: "Details",
},
dashboard: {
title: "Admin-Playground",
description:
"Eine minimale Anwendung zum Ausprobieren der Meteor App-Shell: Navigation, Seitenleiste, Drawer auf kleinen Bildschirmen, Design und Sprache.",
},
cms: {
back: "Zurück",
},
notFound: {
title: "Seite nicht gefunden",
description: "Die Seite, die du suchst, gibt es nicht.",
home: "Zum Dashboard",
},
settings: {
title: "Benutzereinstellungen",
language: "Sprache",
theme: "Design",
reset: "Einstellungen zurücksetzen",
resetTitle: "Einstellungen zurücksetzen?",
resetText:
"Sprache und Design werden auf ihre Standardwerte zurückgesetzt.",
cancel: "Abbrechen",
resetDone: "Einstellungen zurückgesetzt",
},
};
39 changes: 39 additions & 0 deletions examples/playground-admin/src/i18n/en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export const en = {
app: {
title: "Meteor playground",
},
nav: {
label: "Main navigation",
dashboard: "Dashboard",
cms: "CMS",
settings: "Settings",
},
sidebar: {
label: "Details",
},
dashboard: {
title: "Admin playground",
description:
"A minimal application for trying out the Meteor app shell: navigation, sidebar, drawers on small screens, theme and language.",
},
cms: {
back: "Back",
},
notFound: {
title: "Page not found",
description: "The page you are looking for doesn't exist.",
home: "Go to the dashboard",
},
settings: {
title: "User settings",
language: "Language",
theme: "Theme",
reset: "Reset settings",
resetTitle: "Reset settings?",
resetText: "Language and theme go back to their defaults.",
cancel: "Cancel",
resetDone: "Settings reset",
},
};

export type Messages = typeof en;
23 changes: 23 additions & 0 deletions examples/playground-admin/src/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { watch } from "vue";
import { createI18n } from "vue-i18n";
import { de } from "./de";
import { en } from "./en";

const LOCALE_STORAGE_KEY = "playground-admin-locale";

export const i18n = createI18n({
legacy: false,
locale: localStorage.getItem(LOCALE_STORAGE_KEY) === "de" ? "de" : "en",
fallbackLocale: "en",
messages: { en, de },
});

// Remembers the language and sets it on the document, so screen readers pronounce the page in it.
watch(
i18n.global.locale,
(locale) => {
document.documentElement.lang = locale;
localStorage.setItem(LOCALE_STORAGE_KEY, locale);
},
{ immediate: true },
);
14 changes: 14 additions & 0 deletions examples/playground-admin/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createApp } from "vue";
import { DeviceHelperPlugin } from "@shopware-ag/meteor-component-library";
import "@shopware-ag/meteor-component-library/styles.css";
import "@shopware-ag/meteor-component-library/font.css";
import "./assets/main.css";
import App from "./App.vue";
import { router } from "./router";
import { i18n } from "./i18n";

// DeviceHelperPlugin is required by mt-tabs.
const app = createApp(App).use(i18n).use(router).use(DeviceHelperPlugin);

// Mounting after the first route resolves lets the shell apply the route's regions from the first render.
router.isReady().then(() => app.mount("#app"));
55 changes: 55 additions & 0 deletions examples/playground-admin/src/router/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { watch } from "vue";
import { createRouter, createWebHistory } from "vue-router";
import { i18n } from "../i18n";

declare module "vue-router" {
interface RouteMeta {
/** The i18n key of the page title. */
title?: string;
}
}

export const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/",
name: "dashboard",
component: () => import("../views/DashboardView.vue"),
meta: { title: "nav.dashboard" },
},
{
path: "/cms",
name: "cms",
component: () => import("../views/CmsView.vue"),
// A full-screen editor: the shell hides its regions before the page renders.
meta: {
title: "nav.cms",
mtAppRegions: { header: false, navigation: false, sidebar: false },
},
},
{
path: "/settings",
name: "settings",
component: () => import("../views/SettingsView.vue"),
meta: { title: "nav.settings" },
},
{
path: "/:pathMatch(.*)*",
name: "not-found",
component: () => import("../views/NotFoundView.vue"),
meta: { title: "notFound.title" },
},
],
});

/** Shows the page in the browser tab. The shell announces the new title to screen readers. */
function updateTitle() {
const { t } = i18n.global;
const page = router.currentRoute.value.meta.title;

document.title = page ? `${t(page)} · ${t("app.title")}` : t("app.title");
}

router.afterEach(updateTitle);
watch(i18n.global.locale, updateTitle);
Loading
Loading