@multiplatform.one/cli 6.4.3 → 6.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -1
- package/lib/bin/multiplatformOne.mjs +5 -3
- package/lib/commands/initApp.mjs +209 -8
- package/lib/commands/updateApp.mjs +170 -16
- package/package.json +3 -3
- package/src/bin/multiplatformOne.ts +14 -1
- package/src/commands/initApp.spec.ts +369 -3
- package/src/commands/initApp.ts +324 -4
- package/src/commands/updateApp.spec.ts +81 -0
- package/src/commands/updateApp.ts +212 -6
- package/templates/app/apps/__NAME__/package.json +2 -1
- package/templates/app/features/__NAME__/package.json +1 -1
- package/templates/app/packages/config/package.json +1 -1
- package/templates/pieces/frappe/universal/README.md.partial +32 -0
- package/templates/pieces/frappe/universal/docker/compose.frappe.yaml +52 -0
- package/templates/pieces/frappe/universal/env.example.partial +8 -0
- package/templates/pieces/frappe/universal/packages/config/config.json.partial +3 -0
- package/templates/pieces/gnome/universal/README.md.partial +68 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/gnome/main.tsx +165 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/gnome/polyfills.ts +10 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/gnome/shims/components.ts +36 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/gnome/shims/empty-module.ts +28 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/gnome/shims/forms.ts +18 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/gnome/shims/one.ts +89 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/gnome/shims/theme.ts +25 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/gnome/tamagui-barrel.ts +77 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/package.json.partial +18 -0
- package/templates/pieces/gnome/universal/apps/__NAME__/vite.config.gnome.ts +124 -0
- package/templates/pieces/gnome/universal/gitignore.partial +3 -0
- package/templates/pieces/gnome/universal/package.json.partial +6 -0
- package/templates/pieces/keycloak/universal/README.md.partial +19 -0
- package/templates/pieces/keycloak/universal/docker/compose.keycloak.yaml +27 -0
- package/templates/pieces/keycloak/universal/docker/keycloak/realm.json +43 -0
- package/templates/pieces/keycloak/universal/env.example.partial +9 -0
- package/templates/pieces/keycloak/universal/packages/config/config.json.partial +9 -0
- package/templates/pieces/tauri/universal/README.md.partial +18 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/package.json.partial +10 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/Cargo.toml +26 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/build.rs +3 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/capabilities/default.json +7 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/icons/128x128.png +0 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/icons/128x128@2x.png +0 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/icons/32x32.png +0 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/icons/icon.icns +0 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/icons/icon.ico +0 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/lib.rs +14 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/main.rs +9 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/tauri.conf.json +43 -0
- package/templates/pieces/tauri/universal/gitignore.partial +3 -0
- package/templates/pieces/tauri/universal/package.json.partial +6 -0
- package/templates/pieces/vscode/universal/README.md.partial +17 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/package.json.partial +19 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vite.config.vscode.ts +17 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/extension/env.d.ts +1 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/extension/index.ts +13 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/extension/views/helper.ts +14 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/extension/views/panel.ts +38 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/index.html +49 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/manifest.ts +33 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/package.json +7 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/tamagui.css +3 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/tsconfig.json +9 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/app.tsx +24 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/components/ErrorBoundary.tsx +41 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/fonts/inter-400.woff2 +0 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/fonts/inter-700.woff2 +0 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/fonts.css +21 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/main.tsx +35 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/router.tsx +58 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/useVSCodeTheme.ts +56 -0
- package/templates/pieces/vscode/universal/apps/__NAME__/vscode/webview/utils/vscode.ts +16 -0
- package/templates/pieces/vscode/universal/gitignore.partial +2 -0
- package/templates/pieces/vscode/universal/package.json.partial +6 -0
- package/templates/pieces/webext/universal/README.md.partial +16 -0
- package/templates/pieces/webext/universal/apps/__NAME__/package.json.partial +22 -0
- package/templates/pieces/webext/universal/apps/__NAME__/tsconfig.json.partial +5 -0
- package/templates/pieces/webext/universal/apps/__NAME__/vite.config.webext-background.ts +19 -0
- package/templates/pieces/webext/universal/apps/__NAME__/vite.config.webext.ts +35 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/assets/fonts/inter-400.woff2 +0 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/assets/fonts/inter-700.woff2 +0 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/background/main.ts +10 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/components/ErrorBoundary.tsx +41 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/env.ts +2 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/manifest.ts +45 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/prepare.ts +21 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/static/assets/icon-512.png +0 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/tamagui.css +3 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/tsconfig.json +9 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/views/popup/index.html +77 -0
- package/templates/pieces/webext/universal/apps/__NAME__/webext/views/popup/main.tsx +73 -0
- package/templates/pieces/webext/universal/gitignore.partial +2 -0
- package/templates/pieces/webext/universal/package.json.partial +6 -0
- package/templates/universal/apps/__NAME__/package.json +2 -1
- package/templates/universal/features/__NAME__/package.json +1 -1
- package/templates/universal/packages/config/package.json +1 -1
- package/templates/universal/packages/i18n/package.json +1 -1
- package/templates/universal/packages/themes/package.json +1 -1
- package/types/commands/initApp.d.ts +43 -0
- package/types/commands/initApp.d.ts.map +1 -1
- package/types/commands/updateApp.d.ts +4 -0
- package/types/commands/updateApp.d.ts.map +1 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Browser-API polyfills for the GNOME target. MUST be the first import of
|
|
2
|
+
// gnome/main.tsx: JS imports are hoisted, so first-import order is what
|
|
3
|
+
// guarantees window/document/matchMedia/URL exist before Tamagui and the
|
|
4
|
+
// RN-shaped dependencies probe for them at module-init time.
|
|
5
|
+
//
|
|
6
|
+
// The implementation is packaged — @react-gnome/react-native/polyfills
|
|
7
|
+
// installs each global conditionally, so anything you define before this
|
|
8
|
+
// import wins. Keep this file as the app's stable local import point.
|
|
9
|
+
|
|
10
|
+
import "@react-gnome/react-native/polyfills";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// GNOME-target shim for @multiplatform.one/components.
|
|
2
|
+
//
|
|
3
|
+
// The real barrel re-exports the whole library, including modules that
|
|
4
|
+
// pull expo-asset, @shopify/flash-list, @tanstack/react-virtual and
|
|
5
|
+
// @phosphor-icons/react. Under GJS those fail at resolve or module-init
|
|
6
|
+
// time — before a single widget is constructed.
|
|
7
|
+
//
|
|
8
|
+
// The scaffolded screens consume the page shell (Screen, EmptyState,
|
|
9
|
+
// PageHeader, PageSection) plus the layout and text primitives the real
|
|
10
|
+
// barrel gets from its trailing `export * from "tamagui"`. Re-export
|
|
11
|
+
// exactly that. Add modules as your screens grow; a missing export is a
|
|
12
|
+
// build error naming the symbol, which is the cheapest possible signal.
|
|
13
|
+
//
|
|
14
|
+
// Deep `…/src/*` paths rather than the bare package name: the bare name
|
|
15
|
+
// is aliased to THIS file, so importing it here would loop.
|
|
16
|
+
|
|
17
|
+
export * from "@multiplatform.one/components/src/layouts/page";
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
Button,
|
|
21
|
+
Card,
|
|
22
|
+
H1,
|
|
23
|
+
H2,
|
|
24
|
+
H3,
|
|
25
|
+
H4,
|
|
26
|
+
Image,
|
|
27
|
+
Paragraph,
|
|
28
|
+
ScrollView,
|
|
29
|
+
Separator,
|
|
30
|
+
SizableText,
|
|
31
|
+
Spinner,
|
|
32
|
+
Text,
|
|
33
|
+
XStack,
|
|
34
|
+
YStack,
|
|
35
|
+
isWeb,
|
|
36
|
+
} from "../tamagui-barrel";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Stub for real-RN Flow internals and the expo surface, wired up by
|
|
2
|
+
// vite.config.gnome.ts's stubRnLibraries plugin.
|
|
3
|
+
//
|
|
4
|
+
// Two ways they reach the graph: a dependency deep-imports
|
|
5
|
+
// `react-native/Libraries/...` (slipping past the package-root alias),
|
|
6
|
+
// and expo modules arrive through accidental native-condition resolution.
|
|
7
|
+
// Neither has a GJS implementation, and RN's Flow sources cannot be
|
|
8
|
+
// parsed by the bundler at all.
|
|
9
|
+
//
|
|
10
|
+
// The named exports exist so a destructuring import resolves rather than
|
|
11
|
+
// throwing at module init — the call sites are all on paths this target
|
|
12
|
+
// does not take.
|
|
13
|
+
|
|
14
|
+
export default {};
|
|
15
|
+
export const get = () => null;
|
|
16
|
+
export const Platform = {
|
|
17
|
+
OS: "linux",
|
|
18
|
+
select: (o: Record<string, unknown>) => o.default ?? o.native,
|
|
19
|
+
};
|
|
20
|
+
export const NativeEventEmitter = class NativeEventEmitter {};
|
|
21
|
+
export const EventEmitter = class EventEmitter {};
|
|
22
|
+
export const NativeModule = class NativeModule {};
|
|
23
|
+
export const SharedObject = class SharedObject {};
|
|
24
|
+
export const SharedRef = class SharedRef {};
|
|
25
|
+
export const CodedError = class CodedError extends Error {};
|
|
26
|
+
export const UnavailabilityError = class UnavailabilityError extends Error {};
|
|
27
|
+
export const requireNativeModule = () => ({});
|
|
28
|
+
export const requireNativeViewManager = () => null;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// GNOME-target shim for @multiplatform.one/forms.
|
|
2
|
+
//
|
|
3
|
+
// The real barrel reaches the whole field library, and with it phosphor
|
|
4
|
+
// icons, lucide and the expo surface (camera for the barcode field, the
|
|
5
|
+
// linear-gradient for the colour picker). None of those resolve under
|
|
6
|
+
// GJS.
|
|
7
|
+
//
|
|
8
|
+
// Re-export the fields the starter ContactForm uses, through deep
|
|
9
|
+
// `…/src/*` paths — the bare package name is aliased to this file.
|
|
10
|
+
// Adding a field is one line here plus, usually, one granular @tamagui/*
|
|
11
|
+
// export in ../tamagui-barrel.ts.
|
|
12
|
+
|
|
13
|
+
export { Button } from "@multiplatform.one/forms/src/Button";
|
|
14
|
+
export type { ButtonProps } from "@multiplatform.one/forms/src/Button";
|
|
15
|
+
export { Input } from "@multiplatform.one/forms/src/fields/Input";
|
|
16
|
+
export { TextArea } from "@multiplatform.one/forms/src/fields/TextArea";
|
|
17
|
+
export { Spinner } from "@multiplatform.one/forms/src/Spinner";
|
|
18
|
+
export { zIndex } from "@multiplatform.one/forms/src/shared/zIndex";
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// GNOME-target shim for the `one` router package.
|
|
2
|
+
//
|
|
3
|
+
// One's file router never mounts under GJS: its native path goes through
|
|
4
|
+
// react-navigation and react-native-screens, which need the RN fabric
|
|
5
|
+
// renderer. So the router API the screens call is backed instead by the
|
|
6
|
+
// framework's navigator seam (@multiplatform.one/router/seam), which
|
|
7
|
+
// vite.config.gnome.ts resolves to the navigator source alone — the seam
|
|
8
|
+
// barrel also exports a DOM host that has no GJS story.
|
|
9
|
+
//
|
|
10
|
+
// DEGRADATION IS DELIBERATE. gnome/main.tsx renders one screen with no
|
|
11
|
+
// Adw.NavigationView attached, so the navigator is unconfigured: pushes
|
|
12
|
+
// are ignored and Link renders its children in place. Attach a
|
|
13
|
+
// NavigationView host and the same calls become real push/pop with the
|
|
14
|
+
// window back button, Escape and swipe-back all working. Nothing here
|
|
15
|
+
// changes when you do.
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
hrefToString,
|
|
19
|
+
stackNavigator,
|
|
20
|
+
useNavState,
|
|
21
|
+
useRouteParams,
|
|
22
|
+
type Href,
|
|
23
|
+
type NavParams,
|
|
24
|
+
} from "@multiplatform.one/router/seam";
|
|
25
|
+
import type { ReactNode } from "react";
|
|
26
|
+
import { createElement } from "react";
|
|
27
|
+
import { View } from "../tamagui-barrel";
|
|
28
|
+
|
|
29
|
+
// One's router object is referentially stable — consumers put it in
|
|
30
|
+
// useEffect and useCallback dependency arrays, so this one must be too.
|
|
31
|
+
const ROUTER = {
|
|
32
|
+
push: (href: Href) => stackNavigator.push(href),
|
|
33
|
+
replace: (href: Href) => stackNavigator.replace(href),
|
|
34
|
+
back: () => stackNavigator.back(),
|
|
35
|
+
setParams: (params: NavParams) => stackNavigator.setParams(params),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function useRouter(): typeof ROUTER {
|
|
39
|
+
return ROUTER;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function usePathname(): string {
|
|
43
|
+
return useNavState().pathname;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function useParams(): NavParams {
|
|
47
|
+
return useRouteParams();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function useLocalSearchParams(): NavParams {
|
|
51
|
+
return useRouteParams();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface LinkProps {
|
|
55
|
+
href?: Href;
|
|
56
|
+
children?: ReactNode;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function Link({ href, children }: LinkProps): ReactNode {
|
|
61
|
+
if (!href) return children ?? null;
|
|
62
|
+
return createElement(
|
|
63
|
+
View as never,
|
|
64
|
+
{
|
|
65
|
+
cursor: "pointer",
|
|
66
|
+
onPress: () => stackNavigator.push(href),
|
|
67
|
+
testID: `link:${hrefToString(href)}`,
|
|
68
|
+
} as never,
|
|
69
|
+
children,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** One renders the active child route into a layout's <Slot />. Under the
|
|
74
|
+
* seam every route is its own Adw.NavigationPage mounted by the
|
|
75
|
+
* navigation host, so a layout contributes chrome only and this renders
|
|
76
|
+
* nothing by design. */
|
|
77
|
+
export function Slot(): null {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** One's history-nav guard. There is no browser history to block here, so
|
|
82
|
+
* this always reports unblocked. Shape matches One's return value. */
|
|
83
|
+
export function useBlocker(): {
|
|
84
|
+
state: "unblocked" | "blocked" | "proceeding";
|
|
85
|
+
proceed: () => void;
|
|
86
|
+
reset: () => void;
|
|
87
|
+
} {
|
|
88
|
+
return { state: "unblocked", proceed: () => {}, reset: () => {} };
|
|
89
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// GNOME-target shim for @multiplatform.one/theme.
|
|
2
|
+
//
|
|
3
|
+
// The real barrel re-exports devtools, cookie and audit modules whose
|
|
4
|
+
// graphs reach react-dom/server, react-cookie, node:fs and
|
|
5
|
+
// @multiplatform.one/platform (→ expo-constants). None of that belongs in
|
|
6
|
+
// a GJS bundle, and several fail at module init.
|
|
7
|
+
//
|
|
8
|
+
// Re-export only the pure theme-building and knob-resolution subgraph:
|
|
9
|
+
// @package/themes needs the theme builders and fonts, and the page-shell
|
|
10
|
+
// components need the knob resolver.
|
|
11
|
+
//
|
|
12
|
+
// Deep `…/src/*` paths rather than the bare package name, which is
|
|
13
|
+
// aliased to this file and would loop.
|
|
14
|
+
|
|
15
|
+
export * from "@multiplatform.one/theme/src/font";
|
|
16
|
+
export * from "@multiplatform.one/theme/src/theme/createDefaultThemeConfig";
|
|
17
|
+
export * from "@multiplatform.one/theme/src/theme/createThemes";
|
|
18
|
+
export * from "@multiplatform.one/theme/src/theme/intents";
|
|
19
|
+
export * from "@multiplatform.one/theme/src/theme/knobs";
|
|
20
|
+
export * from "@multiplatform.one/theme/src/theme/PresetContext";
|
|
21
|
+
export * from "@multiplatform.one/theme/src/theme/presets";
|
|
22
|
+
export * from "@multiplatform.one/theme/src/theme/recipes";
|
|
23
|
+
export * from "@multiplatform.one/theme/src/theme/resolveKnobs";
|
|
24
|
+
export * from "@multiplatform.one/theme/src/theme/shared";
|
|
25
|
+
export * from "@multiplatform.one/theme/src/theme/useResolvedKnobs";
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Resolution target for the `tamagui` meta-package on the GNOME target.
|
|
2
|
+
//
|
|
3
|
+
// vite.config.gnome.ts aliases `tamagui` here. The full meta-barrel drags
|
|
4
|
+
// web-only components into the GJS bundle, so re-export only the granular
|
|
5
|
+
// @tamagui/* packages this app's graph actually reaches.
|
|
6
|
+
//
|
|
7
|
+
// KEEP THIS MINIMAL, AND EXTEND DELIBERATELY. Every extra granular
|
|
8
|
+
// package widens the module graph, and some widen it off a cliff:
|
|
9
|
+
// @tamagui/popover pulls @tamagui/portal, which requires
|
|
10
|
+
// react-native/Libraries/* — real RN's Flow sources, which the bundler
|
|
11
|
+
// cannot parse. When a screen needs a component, add it here and rebuild;
|
|
12
|
+
// a missing export fails loudly at build time, which is the point.
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
createFont,
|
|
16
|
+
createStyledContext,
|
|
17
|
+
createTamagui,
|
|
18
|
+
getConfig,
|
|
19
|
+
getTokenValue,
|
|
20
|
+
getTokens,
|
|
21
|
+
getVariable,
|
|
22
|
+
getVariableValue,
|
|
23
|
+
isWeb,
|
|
24
|
+
styled,
|
|
25
|
+
TamaguiProvider,
|
|
26
|
+
Text,
|
|
27
|
+
Theme,
|
|
28
|
+
useDidFinishSSR,
|
|
29
|
+
useEvent,
|
|
30
|
+
useMedia,
|
|
31
|
+
useProps,
|
|
32
|
+
useStyle,
|
|
33
|
+
useTheme,
|
|
34
|
+
useThemeName,
|
|
35
|
+
View,
|
|
36
|
+
withStaticProperties,
|
|
37
|
+
} from "@tamagui/core";
|
|
38
|
+
export { H1, H2, H3, H4, H5, H6, Paragraph, SizableText } from "@tamagui/text";
|
|
39
|
+
export { ThemeableStack, XStack, YStack, ZStack } from "@tamagui/stacks";
|
|
40
|
+
export { ScrollView } from "@tamagui/scroll-view";
|
|
41
|
+
export { Separator } from "@tamagui/separator";
|
|
42
|
+
export { Spacer } from "@tamagui/spacer";
|
|
43
|
+
export { Spinner } from "@tamagui/spinner";
|
|
44
|
+
export { Card } from "@tamagui/card";
|
|
45
|
+
export { Image } from "@tamagui/image";
|
|
46
|
+
|
|
47
|
+
// Starter form (features/__NAME__/src/ContactForm.tsx). Each stays inside
|
|
48
|
+
// the core + stacks + helpers subgraph — verified free of
|
|
49
|
+
// react-native/Libraries deep imports.
|
|
50
|
+
export { Button } from "@tamagui/button";
|
|
51
|
+
export { Form } from "@tamagui/form";
|
|
52
|
+
export { Input, TextArea } from "@tamagui/input";
|
|
53
|
+
export { Label } from "@tamagui/label";
|
|
54
|
+
export { getFontSize } from "@tamagui/font-size";
|
|
55
|
+
export { useComposedRefs } from "@tamagui/compose-refs";
|
|
56
|
+
export { useControllableState } from "@tamagui/use-controllable-state";
|
|
57
|
+
export { useWindowDimensions } from "@tamagui/use-window-dimensions";
|
|
58
|
+
|
|
59
|
+
// Type-only names referenced by `import type { … } from "tamagui"` across
|
|
60
|
+
// the workspace. Erased at build time; listed for tsc and editors.
|
|
61
|
+
export type {
|
|
62
|
+
ColorTokens,
|
|
63
|
+
CreateTamaguiProps,
|
|
64
|
+
FontSizeTokens,
|
|
65
|
+
GenericFont,
|
|
66
|
+
GetProps,
|
|
67
|
+
ScrollViewProps,
|
|
68
|
+
SizeTokens,
|
|
69
|
+
TamaguiElement,
|
|
70
|
+
TextProps,
|
|
71
|
+
ThemeName,
|
|
72
|
+
ViewProps,
|
|
73
|
+
} from "@tamagui/core";
|
|
74
|
+
export type { StackProps, XStackProps, YStackProps } from "@tamagui/stacks";
|
|
75
|
+
export type { ButtonProps } from "@tamagui/button";
|
|
76
|
+
export type { InputProps } from "@tamagui/input";
|
|
77
|
+
export type { LabelProps } from "@tamagui/label";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"build:gnome": "vite build --config vite.config.gnome.ts",
|
|
4
|
+
"gnome": "pnpm build:gnome && gjs -m ./dist/gnome/main.js interactive",
|
|
5
|
+
"gnome:capture": "pnpm build:gnome && gjs -m ./dist/gnome/main.js"
|
|
6
|
+
},
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@react-gnome/animation": "^0.1.0",
|
|
9
|
+
"@react-gnome/react-native": "^0.1.0",
|
|
10
|
+
"@react-gnome/react-native-svg": "^0.1.0",
|
|
11
|
+
"@react-gnome/renderer": "^0.1.0",
|
|
12
|
+
"@react-gnome/tamagui": "^0.1.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@multiplatform.one/vite-plugin-gnome": "__MPO_VERSION__",
|
|
16
|
+
"@react-gnome/vite-plugin": "^0.1.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// Vite config for the GNOME (GTK4 / GJS / libadwaita) target.
|
|
2
|
+
//
|
|
3
|
+
// Builds gnome/main.tsx into dist/gnome/main.js, runnable with:
|
|
4
|
+
//
|
|
5
|
+
// pnpm gnome # interactive window
|
|
6
|
+
// pnpm gnome:capture # render, save a PNG, quit
|
|
7
|
+
//
|
|
8
|
+
// THIS IS NOT A VARIANT OF THE WEB BUILD. The web target is One (file
|
|
9
|
+
// router, SSR, react-native-web); this one is a plain Vite library build
|
|
10
|
+
// whose output GJS executes directly, rendering REAL GTK4 widgets through
|
|
11
|
+
// react-gnome — no webview, no DOM. That is the whole difference from the
|
|
12
|
+
// tauri piece, which ships the web build inside a system webview.
|
|
13
|
+
//
|
|
14
|
+
// The generic react-gnome settings (aliases, conditions, define, React
|
|
15
|
+
// dedupe, .native.* extensions) come from @react-gnome/vite-plugin; the
|
|
16
|
+
// Tamagui-under-GJS bundle patches come from
|
|
17
|
+
// @multiplatform.one/vite-plugin-gnome.
|
|
18
|
+
|
|
19
|
+
import { tamaguiLinkedAliases, tamaguiPlugin } from "@multiplatform.one/vite-plugin-gnome";
|
|
20
|
+
import {
|
|
21
|
+
gnomeConditions,
|
|
22
|
+
gnomeDedupe,
|
|
23
|
+
gnomeDefine,
|
|
24
|
+
gnomeExtensions,
|
|
25
|
+
gnomeLinkedAliases,
|
|
26
|
+
} from "@react-gnome/vite-plugin";
|
|
27
|
+
import react from "@vitejs/plugin-react";
|
|
28
|
+
import { createRequire } from "node:module";
|
|
29
|
+
import { dirname, resolve } from "node:path";
|
|
30
|
+
import type { Plugin } from "vite";
|
|
31
|
+
import { defineConfig } from "vite";
|
|
32
|
+
|
|
33
|
+
const require = createRequire(import.meta.url);
|
|
34
|
+
const nodeEnv = process.env.RGN_PROD === "1" ? "production" : "development";
|
|
35
|
+
const gnomeDir = resolve(import.meta.dirname, "gnome");
|
|
36
|
+
|
|
37
|
+
/** Directory a package resolves to, so aliases point at THIS app's
|
|
38
|
+
* installed copy. pnpm's store layout means a bare package name resolved
|
|
39
|
+
* from a file outside this app (a linked workspace source, a hoisted
|
|
40
|
+
* @tamagui/*) can miss these — absolute paths cannot. */
|
|
41
|
+
function pkgDir(id: string): string {
|
|
42
|
+
return dirname(require.resolve(`${id}/package.json`));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Stub real-RN Flow internals and the expo surface. A dependency that
|
|
46
|
+
* deep-imports `react-native/Libraries/...` slips past the package-root
|
|
47
|
+
* alias, and the bundler cannot parse RN's Flow sources; expo modules
|
|
48
|
+
* arrive through accidental native-condition resolution and have no GJS
|
|
49
|
+
* implementation at all. */
|
|
50
|
+
const stubRnLibraries: Plugin = {
|
|
51
|
+
name: "gnome-stub-rn-libraries",
|
|
52
|
+
enforce: "pre",
|
|
53
|
+
resolveId(id) {
|
|
54
|
+
const stub =
|
|
55
|
+
id.includes("react-native/Libraries/") ||
|
|
56
|
+
id.includes("NativeComponentRegistry") ||
|
|
57
|
+
id.startsWith("expo-") ||
|
|
58
|
+
id.includes("expo-modules-core");
|
|
59
|
+
if (stub) return resolve(gnomeDir, "shims/empty-module.ts");
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default defineConfig({
|
|
64
|
+
// Don't copy public/ (web favicons) or the generated tamagui.css into
|
|
65
|
+
// the GJS bundle directory.
|
|
66
|
+
publicDir: false,
|
|
67
|
+
plugins: [stubRnLibraries, react(), tamaguiPlugin],
|
|
68
|
+
resolve: {
|
|
69
|
+
conditions: [...gnomeConditions],
|
|
70
|
+
alias: [
|
|
71
|
+
...gnomeLinkedAliases(resolve(import.meta.dirname, "node_modules/@react-gnome")),
|
|
72
|
+
// `tamagui` meta-package → a lean barrel re-exporting only the
|
|
73
|
+
// granular @tamagui/* packages this app's graph reaches. The full
|
|
74
|
+
// meta-barrel drags web-only components into the GJS bundle.
|
|
75
|
+
...tamaguiLinkedAliases({ tamaguiBarrel: resolve(gnomeDir, "tamagui-barrel.ts") }),
|
|
76
|
+
// Barrels narrowed for GJS — see gnome/shims/*.ts for what each
|
|
77
|
+
// one drops and why. Exact-name regexes so the shims' own deep
|
|
78
|
+
// `…/src/*` imports don't loop back through the alias.
|
|
79
|
+
{
|
|
80
|
+
find: /^@multiplatform\.one\/components$/,
|
|
81
|
+
replacement: resolve(gnomeDir, "shims/components.ts"),
|
|
82
|
+
},
|
|
83
|
+
{ find: /^@multiplatform\.one\/theme$/, replacement: resolve(gnomeDir, "shims/theme.ts") },
|
|
84
|
+
{ find: /^@multiplatform\.one\/forms$/, replacement: resolve(gnomeDir, "shims/forms.ts") },
|
|
85
|
+
// One's file router never mounts on GJS (react-native-screens is a
|
|
86
|
+
// native-fabric dead end). The shim backs the router API the
|
|
87
|
+
// screens consume with the framework's navigator seam.
|
|
88
|
+
{ find: /^one$/, replacement: resolve(gnomeDir, "shims/one.ts") },
|
|
89
|
+
// The seam BARREL also exports the DOM host and the One adapter,
|
|
90
|
+
// whose @vxrn/color-scheme import has no GJS story. Resolve the
|
|
91
|
+
// navigator source alone.
|
|
92
|
+
{
|
|
93
|
+
find: /^@multiplatform\.one\/router\/seam$/,
|
|
94
|
+
replacement: resolve(pkgDir("@multiplatform.one/router"), "src/seam/navigator.ts"),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
// One React instance. The @react-gnome packages carry their own react
|
|
98
|
+
// and react-reconciler copies; dedupe forces every import (including
|
|
99
|
+
// react-reconciler's CJS require) to this app's root.
|
|
100
|
+
dedupe: [...gnomeDedupe],
|
|
101
|
+
// Metro-style resolution: prefer `.native.*` so platform-split
|
|
102
|
+
// modules pick their native variant under GNOME.
|
|
103
|
+
extensions: [...gnomeExtensions],
|
|
104
|
+
},
|
|
105
|
+
define: gnomeDefine(nodeEnv),
|
|
106
|
+
build: {
|
|
107
|
+
target: "esnext",
|
|
108
|
+
outDir: "dist/gnome",
|
|
109
|
+
emptyOutDir: true,
|
|
110
|
+
// GJS reads the bundle directly — keep it readable and mapped, since
|
|
111
|
+
// a stack trace here is the only debugger you get.
|
|
112
|
+
minify: false,
|
|
113
|
+
sourcemap: "inline",
|
|
114
|
+
lib: {
|
|
115
|
+
entry: resolve(gnomeDir, "main.tsx"),
|
|
116
|
+
formats: ["es"],
|
|
117
|
+
fileName: () => "main.js",
|
|
118
|
+
},
|
|
119
|
+
rollupOptions: {
|
|
120
|
+
// GJS provides these; bundling them is not possible.
|
|
121
|
+
external: [/^gi:\/\//, "system", "console", "cairo"],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## Keycloak auth (`mpo init --keycloak`)
|
|
2
|
+
|
|
3
|
+
`apps/__NAME__/src/app.ts` wires `createApp({ keycloak: … })`: the
|
|
4
|
+
`KeycloakProvider` mounts when `KEYCLOAK_ENABLED=1` and reads
|
|
5
|
+
`KEYCLOAK_BASE_URL` / `KEYCLOAK_REALM` / `KEYCLOAK_CLIENT_ID` /
|
|
6
|
+
`KEYCLOAK_PUBLIC_CLIENT_ID` (all `public` env keys in
|
|
7
|
+
`packages/config/config.json`, loaded from `.env` — start from
|
|
8
|
+
`.env.example`).
|
|
9
|
+
|
|
10
|
+
Run a dev auth server with docker:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
docker compose -f docker/compose.keycloak.yaml up -d
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
First boot imports `docker/keycloak/realm.json`: realm `__NAME__` with the
|
|
17
|
+
two clients above and a `dev` / `dev` user. The admin console lives at
|
|
18
|
+
http://localhost:8080/auth (admin / admin) — manage users, clients, and
|
|
19
|
+
flows there, or edit the realm import stub and recreate the volume.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Dev Keycloak for __NAME__ (mpo init --keycloak).
|
|
2
|
+
#
|
|
3
|
+
# docker compose -f docker/compose.keycloak.yaml up -d
|
|
4
|
+
#
|
|
5
|
+
# start-dev uses the embedded dev database (persisted in the named volume)
|
|
6
|
+
# and imports docker/keycloak/realm.json on first boot — realm "__NAME__"
|
|
7
|
+
# with the clients the KEYCLOAK_* env keys reference, plus a dev/dev user.
|
|
8
|
+
# Admin console: http://localhost:8080/auth (admin/admin).
|
|
9
|
+
services:
|
|
10
|
+
keycloak:
|
|
11
|
+
image: quay.io/keycloak/keycloak:26.6
|
|
12
|
+
command:
|
|
13
|
+
- start-dev
|
|
14
|
+
- --import-realm
|
|
15
|
+
environment:
|
|
16
|
+
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
|
17
|
+
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
|
|
18
|
+
# /auth keeps parity with KEYCLOAK_BASE_URL (and reverse-proxy setups).
|
|
19
|
+
KC_HTTP_RELATIVE_PATH: /auth
|
|
20
|
+
ports:
|
|
21
|
+
- "8080:8080"
|
|
22
|
+
volumes:
|
|
23
|
+
- ./keycloak/realm.json:/opt/keycloak/data/import/realm.json:ro
|
|
24
|
+
- keycloak:/opt/keycloak/data/h2
|
|
25
|
+
|
|
26
|
+
volumes:
|
|
27
|
+
keycloak: {}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"realm": "__NAME__",
|
|
3
|
+
"enabled": true,
|
|
4
|
+
"sslRequired": "none",
|
|
5
|
+
"registrationAllowed": true,
|
|
6
|
+
"clients": [
|
|
7
|
+
{
|
|
8
|
+
"clientId": "__NAME__",
|
|
9
|
+
"name": "__NAME_PASCAL__ (confidential)",
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"protocol": "openid-connect",
|
|
12
|
+
"publicClient": false,
|
|
13
|
+
"secret": "__NAME__-dev-secret",
|
|
14
|
+
"standardFlowEnabled": true,
|
|
15
|
+
"directAccessGrantsEnabled": true,
|
|
16
|
+
"serviceAccountsEnabled": true,
|
|
17
|
+
"redirectUris": ["http://localhost:3456/*"],
|
|
18
|
+
"webOrigins": ["http://localhost:3456"]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"clientId": "__NAME__-public",
|
|
22
|
+
"name": "__NAME_PASCAL__ (public)",
|
|
23
|
+
"enabled": true,
|
|
24
|
+
"protocol": "openid-connect",
|
|
25
|
+
"publicClient": true,
|
|
26
|
+
"standardFlowEnabled": true,
|
|
27
|
+
"directAccessGrantsEnabled": true,
|
|
28
|
+
"redirectUris": ["http://localhost:3456/*"],
|
|
29
|
+
"webOrigins": ["http://localhost:3456"]
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"users": [
|
|
33
|
+
{
|
|
34
|
+
"username": "dev",
|
|
35
|
+
"enabled": true,
|
|
36
|
+
"emailVerified": true,
|
|
37
|
+
"email": "dev@__NAME__.localhost",
|
|
38
|
+
"firstName": "Dev",
|
|
39
|
+
"lastName": "User",
|
|
40
|
+
"credentials": [{ "type": "password", "value": "dev", "temporary": false }]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Keycloak auth (mpo init --keycloak) — copy to .env. KEYCLOAK_ENABLED=1
|
|
2
|
+
# mounts the KeycloakProvider wired in apps/__NAME__/src/app.ts; the other
|
|
3
|
+
# keys must match the realm import (docker/keycloak/realm.json).
|
|
4
|
+
KEYCLOAK_ENABLED=1
|
|
5
|
+
# Auth server base URL (docker/compose.keycloak.yaml serves /auth on :8080).
|
|
6
|
+
KEYCLOAK_BASE_URL=http://localhost:8080/auth
|
|
7
|
+
KEYCLOAK_REALM=__NAME__
|
|
8
|
+
KEYCLOAK_CLIENT_ID=__NAME__
|
|
9
|
+
KEYCLOAK_PUBLIC_CLIENT_ID=__NAME__-public
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
## Desktop app (`mpo init --tauri`)
|
|
2
|
+
|
|
3
|
+
`apps/__NAME__/src-tauri/` is a minimal [Tauri v2](https://tauri.app) shell
|
|
4
|
+
around the web app. It needs the platform prerequisites (Rust toolchain +
|
|
5
|
+
system webview libraries): https://tauri.app/start/prerequisites/
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm tauri:dev # dev window against the vite dev server (:3456)
|
|
9
|
+
pnpm tauri:build # bundle installers (runs pnpm build first)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`tauri:dev` starts `pnpm dev` for you (beforeDevCommand) and opens the
|
|
13
|
+
window once http://localhost:3456 responds. Note the web build is an SSR
|
|
14
|
+
One app: `tauri:build` embeds `apps/__NAME__/dist` as-is, which suits a
|
|
15
|
+
static/SPA export — point `frontendDist` (src-tauri/tauri.conf.json) at
|
|
16
|
+
your static output, or keep the desktop shell against a served URL.
|
|
17
|
+
Regenerate icons from your own artwork with
|
|
18
|
+
`pnpm --filter @app/__NAME__ tauri icon <path/to/icon.png>`.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "__NAME__"
|
|
3
|
+
version = "0.0.0"
|
|
4
|
+
description = "__NAME__ desktop application"
|
|
5
|
+
edition = "2021"
|
|
6
|
+
|
|
7
|
+
[lib]
|
|
8
|
+
name = "app_lib"
|
|
9
|
+
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
10
|
+
|
|
11
|
+
[build-dependencies]
|
|
12
|
+
tauri-build = { version = "2", features = [] }
|
|
13
|
+
|
|
14
|
+
[dependencies]
|
|
15
|
+
tauri = { version = "2", features = [] }
|
|
16
|
+
tauri-plugin-log = "2"
|
|
17
|
+
serde = { version = "1", features = ["derive"] }
|
|
18
|
+
serde_json = "1"
|
|
19
|
+
log = "0.4"
|
|
20
|
+
|
|
21
|
+
[profile.release]
|
|
22
|
+
panic = "abort"
|
|
23
|
+
codegen-units = 1
|
|
24
|
+
lto = true
|
|
25
|
+
opt-level = "s"
|
|
26
|
+
strip = true
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//! __NAME__ Tauri application library. Register #[tauri::command] functions
|
|
2
|
+
//! here (and in the invoke_handler) as the desktop app grows.
|
|
3
|
+
|
|
4
|
+
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
5
|
+
pub fn run() {
|
|
6
|
+
tauri::Builder::default()
|
|
7
|
+
.plugin(
|
|
8
|
+
tauri_plugin_log::Builder::new()
|
|
9
|
+
.level(log::LevelFilter::Info)
|
|
10
|
+
.build(),
|
|
11
|
+
)
|
|
12
|
+
.run(tauri::generate_context!())
|
|
13
|
+
.expect("error while running tauri application");
|
|
14
|
+
}
|