@multiplatform.one/cli 7.11.0 → 7.15.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 +121 -111
- package/bin/createMultiplatformApp.mjs +39 -37
- package/lib/bin/multiplatformOne.mjs +65 -75
- package/lib/commands/addApp.mjs +78 -0
- package/lib/commands/adoptApp.mjs +11 -7
- package/lib/commands/doctypeTypes.mjs +148 -0
- package/lib/commands/e2e.mjs +2 -2
- package/lib/commands/init.mjs +142 -459
- package/lib/commands/merge.mjs +359 -0
- package/lib/commands/pieces.mjs +236 -0
- package/lib/commands/provenance.mjs +108 -0
- package/lib/commands/scaffold.mjs +105 -0
- package/lib/commands/updateApp.mjs +211 -528
- package/lib/source.json +5 -0
- package/lib/source.mjs +63 -0
- package/package.json +6 -6
- package/scripts/frappe-bootstrap.sh +29 -3
- package/scripts/frappe-dev.sh +1 -2
- package/scripts/frappe-helpers.sh +50 -2
- package/scripts/frappe.sh +5 -0
- package/scripts/scaffold.sh +937 -0
- package/scripts/stamp-source.mjs +51 -0
- package/scripts/stamp-source.spec.ts +86 -0
- package/src/bin/multiplatformOne.ts +116 -226
- package/src/commands/addApp.ts +102 -0
- package/src/commands/adoptApp.spec.ts +5 -1
- package/src/commands/adoptApp.ts +15 -10
- package/src/commands/doctypeTypes.spec.ts +155 -0
- package/src/commands/doctypeTypes.ts +214 -0
- package/src/commands/init.spec.ts +66 -0
- package/src/commands/init.ts +201 -643
- package/src/commands/merge.spec.ts +81 -0
- package/src/commands/merge.ts +411 -0
- package/src/commands/pieces.spec.ts +62 -0
- package/src/commands/pieces.ts +340 -0
- package/src/commands/provenance.spec.ts +92 -0
- package/src/commands/provenance.ts +169 -0
- package/src/commands/scaffold.ts +131 -0
- package/src/commands/updateApp.spec.ts +540 -331
- package/src/commands/updateApp.ts +255 -668
- package/src/source.spec.ts +45 -0
- package/src/source.ts +88 -0
- package/templates/AGENTS.md +161 -0
- package/templates/README.md +62 -0
- package/templates/pieces/frappe/universal/README.md.partial +7 -32
- package/templates/pieces/frappe/universal/env.example.partial +3 -3
- package/templates/pieces/frappe-bench/universal/README.md.partial +28 -0
- package/templates/pieces/{frappe → frappe-bench}/universal/docker/compose.frappe.yaml +2 -2
- package/templates/pieces/tauri/universal/README.md.partial +7 -5
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/dev.rs +463 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/lib.rs +6 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/tauri.conf.json +2 -1
- package/templates/pieces/webext/universal/apps/__NAME__/package.json.partial +1 -0
- package/templates/pieces/webext/universal/apps/__NAME__/vite.config.webext.ts +6 -2
- package/types/bin/multiplatformOne.d.ts.map +1 -1
- package/types/commands/addApp.d.ts +20 -0
- package/types/commands/addApp.d.ts.map +1 -0
- package/types/commands/adoptApp.d.ts +4 -3
- package/types/commands/adoptApp.d.ts.map +1 -1
- package/types/commands/doctypeTypes.d.ts +40 -0
- package/types/commands/doctypeTypes.d.ts.map +1 -0
- package/types/commands/init.d.ts +30 -13
- package/types/commands/init.d.ts.map +1 -1
- package/types/commands/merge.d.ts +54 -0
- package/types/commands/merge.d.ts.map +1 -0
- package/types/commands/pieces.d.ts +54 -0
- package/types/commands/pieces.d.ts.map +1 -0
- package/types/commands/provenance.d.ts +52 -0
- package/types/commands/provenance.d.ts.map +1 -0
- package/types/commands/scaffold.d.ts +43 -0
- package/types/commands/scaffold.d.ts.map +1 -0
- package/types/commands/updateApp.d.ts +19 -27
- package/types/commands/updateApp.d.ts.map +1 -1
- package/types/source.d.ts +35 -0
- package/types/source.d.ts.map +1 -0
- package/lib/commands/initApp.mjs +0 -431
- package/lib/generateVscode.mjs +0 -184
- package/scripts/clone.sh +0 -17
- package/scripts/update.sh +0 -46
- package/src/commands/initApp.spec.ts +0 -720
- package/src/commands/initApp.ts +0 -706
- package/src/generateVscode.ts +0 -238
- package/templates/app/AGENTS.md +0 -142
- package/templates/app/README.md +0 -62
- package/templates/app/apps/__NAME__/index.html +0 -36
- package/templates/app/apps/__NAME__/package.json +0 -31
- package/templates/app/apps/__NAME__/public/fonts/inter-400.woff2 +0 -0
- package/templates/app/apps/__NAME__/public/fonts/inter-700.woff2 +0 -0
- package/templates/app/apps/__NAME__/src/App.tsx +0 -9
- package/templates/app/apps/__NAME__/src/main.tsx +0 -14
- package/templates/app/apps/__NAME__/tsconfig.json +0 -8
- package/templates/app/apps/__NAME__/vite.config.ts +0 -17
- package/templates/app/features/__NAME__/package.json +0 -34
- package/templates/app/features/__NAME__/src/HomeScreen.tsx +0 -70
- package/templates/app/features/__NAME__/src/index.ts +0 -1
- package/templates/app/features/__NAME__/tsconfig.json +0 -5
- package/templates/app/gitignore +0 -9
- package/templates/app/npmrc +0 -2
- package/templates/app/oxlintrc.json +0 -39
- package/templates/app/package.json +0 -38
- package/templates/app/packages/config/config.json +0 -4
- package/templates/app/packages/config/index.ts +0 -5
- package/templates/app/packages/config/package.json +0 -17
- package/templates/app/packages/config/tsconfig.json +0 -5
- package/templates/app/pnpm-workspace.yaml +0 -4
- package/templates/app/tsconfig.base.json +0 -16
- package/templates/universal/AGENTS.md +0 -142
- package/templates/universal/README.md +0 -97
- package/templates/universal/apps/__NAME__/app.config.js +0 -31
- package/templates/universal/apps/__NAME__/config/tamagui.config.ts +0 -4
- package/templates/universal/apps/__NAME__/package.json +0 -62
- package/templates/universal/apps/__NAME__/polyfills.native.ts +0 -23
- package/templates/universal/apps/__NAME__/polyfills.ts +0 -3
- package/templates/universal/apps/__NAME__/public/fonts/inter-400.woff2 +0 -0
- package/templates/universal/apps/__NAME__/public/fonts/inter-700.woff2 +0 -0
- package/templates/universal/apps/__NAME__/routes/_layout.tsx +0 -22
- package/templates/universal/apps/__NAME__/routes/_layout.web.tsx +0 -21
- package/templates/universal/apps/__NAME__/routes/about.tsx +0 -3
- package/templates/universal/apps/__NAME__/routes/index.tsx +0 -3
- package/templates/universal/apps/__NAME__/src/app.ts +0 -10
- package/templates/universal/apps/__NAME__/tamagui.css +0 -3
- package/templates/universal/apps/__NAME__/tsconfig.json +0 -8
- package/templates/universal/apps/__NAME__/types.d.ts +0 -9
- package/templates/universal/apps/__NAME__/vite.config.ts +0 -20
- package/templates/universal/features/__NAME__/package.json +0 -35
- package/templates/universal/features/__NAME__/src/AboutScreen.tsx +0 -27
- package/templates/universal/features/__NAME__/src/AppLayout.tsx +0 -50
- package/templates/universal/features/__NAME__/src/ContactForm.spec.tsx +0 -22
- package/templates/universal/features/__NAME__/src/ContactForm.tsx +0 -55
- package/templates/universal/features/__NAME__/src/HomeScreen.tsx +0 -40
- package/templates/universal/features/__NAME__/src/index.ts +0 -4
- package/templates/universal/features/__NAME__/src/screens.spec.ts +0 -12
- package/templates/universal/features/__NAME__/tsconfig.json +0 -5
- package/templates/universal/features/__NAME__/vitest.config.mjs +0 -7
- package/templates/universal/gitignore +0 -14
- package/templates/universal/npmrc +0 -3
- package/templates/universal/oxlintrc.json +0 -39
- package/templates/universal/package.json +0 -51
- package/templates/universal/packages/config/config.json +0 -4
- package/templates/universal/packages/config/index.ts +0 -5
- package/templates/universal/packages/config/package.json +0 -17
- package/templates/universal/packages/config/tsconfig.json +0 -5
- package/templates/universal/packages/i18n/en/common.json +0 -30
- package/templates/universal/packages/i18n/es/common.json +0 -30
- package/templates/universal/packages/i18n/i18n.d.ts +0 -16
- package/templates/universal/packages/i18n/index.ts +0 -26
- package/templates/universal/packages/i18n/package.json +0 -20
- package/templates/universal/packages/i18n/resources.ts +0 -13
- package/templates/universal/packages/i18n/tsconfig.json +0 -5
- package/templates/universal/packages/themes/accent.ts +0 -32
- package/templates/universal/packages/themes/base.ts +0 -50
- package/templates/universal/packages/themes/fonts.ts +0 -8
- package/templates/universal/packages/themes/index.ts +0 -33
- package/templates/universal/packages/themes/package.json +0 -23
- package/templates/universal/packages/themes/tamagui.config.ts +0 -14
- package/templates/universal/packages/themes/tsconfig.json +0 -5
- package/templates/universal/pnpm-workspace.yaml +0 -4
- package/templates/universal/tsconfig.base.json +0 -21
- package/templates/universal/types/env.d.ts +0 -9
- package/types/commands/initApp.d.ts +0 -114
- package/types/commands/initApp.d.ts.map +0 -1
- package/types/generateVscode.d.ts +0 -7
- package/types/generateVscode.d.ts.map +0 -1
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@features/__NAME__",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./src/index.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./src/index.ts",
|
|
9
|
-
"./*": "./src/*.ts"
|
|
10
|
-
},
|
|
11
|
-
"scripts": {
|
|
12
|
-
"test": "vitest run",
|
|
13
|
-
"typecheck": "tsgo --noEmit"
|
|
14
|
-
},
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"@multiplatform.one/components": "__MPO_VERSION__",
|
|
17
|
-
"@multiplatform.one/forms": "__MPO_VERSION__",
|
|
18
|
-
"@multiplatform.one/theme": "__MPO_VERSION__",
|
|
19
|
-
"@package/config": "workspace:*",
|
|
20
|
-
"one": "1.16.5",
|
|
21
|
-
"react": "19.2.5",
|
|
22
|
-
"react-i18next": "^16.6.6"
|
|
23
|
-
},
|
|
24
|
-
"devDependencies": {
|
|
25
|
-
"@multiplatform.one/config": "__MPO_VERSION__",
|
|
26
|
-
"@multiplatform.one/test-utils": "__MPO_VERSION__",
|
|
27
|
-
"@types/react": "~19.2.14",
|
|
28
|
-
"jsdom": "^26.0.0",
|
|
29
|
-
"typescript": "~5.9.3",
|
|
30
|
-
"vitest": "^4.1.5"
|
|
31
|
-
},
|
|
32
|
-
"peerDependencies": {
|
|
33
|
-
"react": "^19.1.0"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Button, H2, Paragraph, Screen, YStack } from "@multiplatform.one/components";
|
|
2
|
-
import { useRouter } from "one";
|
|
3
|
-
import { useTranslation } from "react-i18next";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* About screen (route: /about) — demonstrates programmatic navigation with
|
|
7
|
-
* the router hooks from `one` (same pattern as the framework's own layouts).
|
|
8
|
-
*/
|
|
9
|
-
export function AboutScreen() {
|
|
10
|
-
const { t } = useTranslation();
|
|
11
|
-
const router = useRouter();
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<Screen>
|
|
15
|
-
<YStack gap="$3" alignItems="flex-start">
|
|
16
|
-
<H2>{t("screens.about.title", "About")}</H2>
|
|
17
|
-
<Paragraph color="$color11">
|
|
18
|
-
{t(
|
|
19
|
-
"screens.about.message",
|
|
20
|
-
"This screen lives in features/__NAME__ and is wired to the /about route by apps/__NAME__/routes/about.tsx.",
|
|
21
|
-
)}
|
|
22
|
-
</Paragraph>
|
|
23
|
-
<Button onPress={() => router.navigate("/")}>{t("screens.about.back", "Back home")}</Button>
|
|
24
|
-
</YStack>
|
|
25
|
-
</Screen>
|
|
26
|
-
);
|
|
27
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { Button, SizableText, XStack, YStack } from "@multiplatform.one/components";
|
|
2
|
-
import { usePathname, useRouter } from "one";
|
|
3
|
-
import type { PropsWithChildren } from "react";
|
|
4
|
-
import { useTranslation } from "react-i18next";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Root layout: top navigation + content. Wired into the router by
|
|
8
|
-
* apps/__NAME__/routes/_layout(.web).tsx via createRootLayout. Uses router
|
|
9
|
-
* hooks (not window.location) so it works on native as well as web.
|
|
10
|
-
*/
|
|
11
|
-
export function AppLayout({ children }: PropsWithChildren) {
|
|
12
|
-
const { t } = useTranslation();
|
|
13
|
-
const router = useRouter();
|
|
14
|
-
const path = usePathname() || "/";
|
|
15
|
-
|
|
16
|
-
const items = [
|
|
17
|
-
{ label: t("nav.home", "Home"), href: "/", active: path === "/" },
|
|
18
|
-
{ label: t("nav.about", "About"), href: "/about", active: path.startsWith("/about") },
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<YStack flex={1} backgroundColor="$background">
|
|
23
|
-
<XStack
|
|
24
|
-
alignItems="center"
|
|
25
|
-
gap="$4"
|
|
26
|
-
paddingHorizontal="$4"
|
|
27
|
-
paddingVertical="$3"
|
|
28
|
-
borderBottomWidth={1}
|
|
29
|
-
borderBottomColor="$borderColor"
|
|
30
|
-
>
|
|
31
|
-
<SizableText fontWeight="700" size="$5">
|
|
32
|
-
{t("app.name", "__NAME_PASCAL__")}
|
|
33
|
-
</SizableText>
|
|
34
|
-
<XStack gap="$2" marginLeft="auto">
|
|
35
|
-
{items.map((item) => (
|
|
36
|
-
<Button
|
|
37
|
-
key={item.href}
|
|
38
|
-
size="$3"
|
|
39
|
-
chromeless={!item.active}
|
|
40
|
-
onPress={() => router.navigate(item.href)}
|
|
41
|
-
>
|
|
42
|
-
{item.label}
|
|
43
|
-
</Button>
|
|
44
|
-
))}
|
|
45
|
-
</XStack>
|
|
46
|
-
</XStack>
|
|
47
|
-
{children}
|
|
48
|
-
</YStack>
|
|
49
|
-
);
|
|
50
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
2
|
-
import { fireEvent } from "@testing-library/react";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
import { ContactForm } from "./ContactForm";
|
|
5
|
-
|
|
6
|
-
describe("ContactForm", () => {
|
|
7
|
-
it("renders the starter form fields", () => {
|
|
8
|
-
const result = renderWithProviders(<ContactForm />);
|
|
9
|
-
expect(result.findTextElement("Contact")).toBeDefined();
|
|
10
|
-
expect(result.findTextElement("Name")).toBeDefined();
|
|
11
|
-
expect(result.findTextElement("Message")).toBeDefined();
|
|
12
|
-
expect(result.getButton("Send")).toBeDefined();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("shows required errors when submitting empty", () => {
|
|
16
|
-
const result = renderWithProviders(<ContactForm />);
|
|
17
|
-
const send = result.getButton("Send");
|
|
18
|
-
expect(send).toBeDefined();
|
|
19
|
-
fireEvent.click(send as Element);
|
|
20
|
-
expect(result.findTextElement("This field is required")).toBeDefined();
|
|
21
|
-
});
|
|
22
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { H2, Paragraph, YStack } from "@multiplatform.one/components";
|
|
2
|
-
import { Button, Input, TextArea } from "@multiplatform.one/forms";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { useTranslation } from "react-i18next";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Starter form demonstrating @multiplatform.one/forms fields (Input, TextArea,
|
|
8
|
-
* Button) with the canonical onChangeText/value contract, helper/error slots,
|
|
9
|
-
* and a submit handler. Replace the console.info with a real mutation.
|
|
10
|
-
*/
|
|
11
|
-
export function ContactForm() {
|
|
12
|
-
const { t } = useTranslation();
|
|
13
|
-
const [name, setName] = useState("");
|
|
14
|
-
const [message, setMessage] = useState("");
|
|
15
|
-
const [submitted, setSubmitted] = useState(false);
|
|
16
|
-
const [sent, setSent] = useState(false);
|
|
17
|
-
|
|
18
|
-
const requiredError = t("screens.contact.required", "This field is required");
|
|
19
|
-
|
|
20
|
-
function handleSend() {
|
|
21
|
-
setSubmitted(true);
|
|
22
|
-
if (!name.trim() || !message.trim()) return;
|
|
23
|
-
// eslint-disable-next-line no-console
|
|
24
|
-
console.info("[__NAME__] contact form:", { name, message });
|
|
25
|
-
setSent(true);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<YStack gap="$4" maxWidth={480}>
|
|
30
|
-
<H2>{t("screens.contact.title", "Contact")}</H2>
|
|
31
|
-
<Input
|
|
32
|
-
label={t("screens.contact.name", "Name")}
|
|
33
|
-
placeholder={t("screens.contact.namePlaceholder", "Your name")}
|
|
34
|
-
value={name}
|
|
35
|
-
onChangeText={setName}
|
|
36
|
-
required
|
|
37
|
-
error={submitted && !name.trim() ? requiredError : undefined}
|
|
38
|
-
/>
|
|
39
|
-
<TextArea
|
|
40
|
-
label={t("screens.contact.message", "Message")}
|
|
41
|
-
placeholder={t("screens.contact.messagePlaceholder", "What do you want to say?")}
|
|
42
|
-
value={message}
|
|
43
|
-
onChangeText={setMessage}
|
|
44
|
-
required
|
|
45
|
-
error={submitted && !message.trim() ? requiredError : undefined}
|
|
46
|
-
/>
|
|
47
|
-
<Button onPress={handleSend}>{t("screens.contact.send", "Send")}</Button>
|
|
48
|
-
{sent ? (
|
|
49
|
-
<Paragraph color="$color11">
|
|
50
|
-
{t("screens.contact.sent", "Message sent (demo) — check the console.")}
|
|
51
|
-
</Paragraph>
|
|
52
|
-
) : null}
|
|
53
|
-
</YStack>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { H1, Paragraph, Screen, Separator, YStack } from "@multiplatform.one/components";
|
|
2
|
-
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
3
|
-
import { Link } from "one";
|
|
4
|
-
import { useTranslation } from "react-i18next";
|
|
5
|
-
import { ContactForm } from "./ContactForm";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Home screen (route: /). Keep product UI in features/<name>; the app shell
|
|
9
|
-
* (apps/<name>) only wires routes and providers.
|
|
10
|
-
*/
|
|
11
|
-
export function HomeScreen() {
|
|
12
|
-
const { t } = useTranslation();
|
|
13
|
-
// Knob wiring: spread complete knobProps fragments — never cherry-pick
|
|
14
|
-
// resolved tokens (see AGENTS.md, knobs system).
|
|
15
|
-
const { knobProps } = useResolvedKnobs({ component: "Card" });
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<Screen>
|
|
19
|
-
<YStack
|
|
20
|
-
{...knobProps.surface}
|
|
21
|
-
{...knobProps.borderRadius}
|
|
22
|
-
{...knobProps.panelPadding}
|
|
23
|
-
{...knobProps.gap}
|
|
24
|
-
backgroundColor="$color2"
|
|
25
|
-
borderColor="$borderColor"
|
|
26
|
-
>
|
|
27
|
-
<H1 {...knobProps.heading}>{t("screens.home.welcome", "Welcome to __NAME_PASCAL__")}</H1>
|
|
28
|
-
<Paragraph {...knobProps.body} color="$color11">
|
|
29
|
-
{t(
|
|
30
|
-
"screens.home.message",
|
|
31
|
-
"One codebase — web, iOS, and Android. Edit features/__NAME__/src/HomeScreen.tsx to get started.",
|
|
32
|
-
)}
|
|
33
|
-
</Paragraph>
|
|
34
|
-
<Link href="/about">{t("nav.about", "About")}</Link>
|
|
35
|
-
</YStack>
|
|
36
|
-
<Separator />
|
|
37
|
-
<ContactForm />
|
|
38
|
-
</Screen>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { AboutScreen, AppLayout, ContactForm, HomeScreen } from "./index";
|
|
3
|
-
|
|
4
|
-
// Source-shape smoke: every starter screen is exported and renderable
|
|
5
|
-
// (component functions). Full render coverage lives next to each component.
|
|
6
|
-
describe("feature exports", () => {
|
|
7
|
-
it("exports the starter screens", () => {
|
|
8
|
-
for (const Component of [AboutScreen, AppLayout, ContactForm, HomeScreen]) {
|
|
9
|
-
expect(typeof Component).toBe("function");
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
});
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { createVitestConfig } from "@multiplatform.one/config/vitest";
|
|
2
|
-
|
|
3
|
-
export default createVitestConfig({
|
|
4
|
-
tamaguiConfig: "../../packages/themes/tamagui.config.ts",
|
|
5
|
-
setupFiles: ["@multiplatform.one/test-utils/setup"],
|
|
6
|
-
include: ["src/**/*.spec.{ts,tsx}"],
|
|
7
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
-
"rules": {
|
|
4
|
-
"no-unused-vars": [
|
|
5
|
-
"warn",
|
|
6
|
-
{
|
|
7
|
-
"argsIgnorePattern": "^_",
|
|
8
|
-
"varsIgnorePattern": "^_"
|
|
9
|
-
}
|
|
10
|
-
],
|
|
11
|
-
"no-console": "warn",
|
|
12
|
-
"eqeqeq": "error",
|
|
13
|
-
"no-var": "error",
|
|
14
|
-
"prefer-const": "error"
|
|
15
|
-
},
|
|
16
|
-
"overrides": [
|
|
17
|
-
{
|
|
18
|
-
"files": [
|
|
19
|
-
"apps/**/*.{ts,tsx,js,jsx}",
|
|
20
|
-
"features/**/*.{ts,tsx,js,jsx}",
|
|
21
|
-
"packages/**/*.{ts,tsx,js,jsx}"
|
|
22
|
-
],
|
|
23
|
-
"rules": {
|
|
24
|
-
"no-restricted-imports": [
|
|
25
|
-
"error",
|
|
26
|
-
{
|
|
27
|
-
"paths": [
|
|
28
|
-
{
|
|
29
|
-
"name": "tamagui",
|
|
30
|
-
"message": "Raw tamagui is only allowed inside framework packages. Import from @multiplatform.one/components, @multiplatform.one/forms, or @multiplatform.one/theme. See AGENTS.md."
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
],
|
|
38
|
-
"ignorePatterns": ["**/node_modules/**", "**/dist/**", "**/build/**"]
|
|
39
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "__NAME__",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"description": "__NAME__ — multiplatform.one universal app (web + iOS + Android)",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"dev": "pnpm --filter @app/__NAME__ dev",
|
|
9
|
-
"build": "pnpm --filter @app/__NAME__ build",
|
|
10
|
-
"serve": "pnpm --filter @app/__NAME__ serve",
|
|
11
|
-
"native": "pnpm --filter @app/__NAME__ prebuild:native",
|
|
12
|
-
"ios": "pnpm --filter @app/__NAME__ ios",
|
|
13
|
-
"android": "pnpm --filter @app/__NAME__ android",
|
|
14
|
-
"test": "pnpm -r test",
|
|
15
|
-
"lint": "oxlint -c oxlintrc.json .",
|
|
16
|
-
"typecheck": "pnpm -r typecheck"
|
|
17
|
-
},
|
|
18
|
-
"devDependencies": {
|
|
19
|
-
"@types/chrome": "^0.2.5",
|
|
20
|
-
"@types/firefox-webext-browser": "^143.0.0",
|
|
21
|
-
"oxlint": "^1.62.0"
|
|
22
|
-
},
|
|
23
|
-
"engines": {
|
|
24
|
-
"node": ">=20"
|
|
25
|
-
},
|
|
26
|
-
"packageManager": "pnpm@10.32.1",
|
|
27
|
-
"pnpm": {
|
|
28
|
-
"overrides": {
|
|
29
|
-
"react-dom": "19.2.5",
|
|
30
|
-
"react-native-reanimated": "4.2.1",
|
|
31
|
-
"react-native-worklets": "0.7.4"
|
|
32
|
-
},
|
|
33
|
-
"peerDependencyRules": {
|
|
34
|
-
"allowedVersions": {
|
|
35
|
-
"react": "19",
|
|
36
|
-
"react-native": "0.83",
|
|
37
|
-
"@react-navigation/native": "7",
|
|
38
|
-
"vite": "8",
|
|
39
|
-
"expo-constants": "55",
|
|
40
|
-
"rehype-autolink-headings": "7",
|
|
41
|
-
"rehype-slug": "6",
|
|
42
|
-
"remark-mdx-frontmatter": "5"
|
|
43
|
-
},
|
|
44
|
-
"ignoreMissing": [
|
|
45
|
-
"@react-navigation/native",
|
|
46
|
-
"@types/emscripten",
|
|
47
|
-
"react-native"
|
|
48
|
-
]
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@package/config",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./index.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./index.ts",
|
|
9
|
-
"./config.json": "./config.json"
|
|
10
|
-
},
|
|
11
|
-
"scripts": {
|
|
12
|
-
"typecheck": "tsgo --noEmit"
|
|
13
|
-
},
|
|
14
|
-
"devDependencies": {
|
|
15
|
-
"typescript": "~5.9.3"
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"app": {
|
|
3
|
-
"name": "__NAME_PASCAL__"
|
|
4
|
-
},
|
|
5
|
-
"nav": {
|
|
6
|
-
"home": "Home",
|
|
7
|
-
"about": "About"
|
|
8
|
-
},
|
|
9
|
-
"screens": {
|
|
10
|
-
"home": {
|
|
11
|
-
"welcome": "Welcome to __NAME_PASCAL__",
|
|
12
|
-
"message": "One codebase — web, iOS, and Android. Edit features/__NAME__/src/HomeScreen.tsx to get started."
|
|
13
|
-
},
|
|
14
|
-
"about": {
|
|
15
|
-
"title": "About",
|
|
16
|
-
"message": "This screen lives in features/__NAME__ and is wired to the /about route by apps/__NAME__/routes/about.tsx.",
|
|
17
|
-
"back": "Back home"
|
|
18
|
-
},
|
|
19
|
-
"contact": {
|
|
20
|
-
"title": "Contact",
|
|
21
|
-
"name": "Name",
|
|
22
|
-
"namePlaceholder": "Your name",
|
|
23
|
-
"message": "Message",
|
|
24
|
-
"messagePlaceholder": "What do you want to say?",
|
|
25
|
-
"send": "Send",
|
|
26
|
-
"required": "This field is required",
|
|
27
|
-
"sent": "Message sent (demo) — check the console."
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"app": {
|
|
3
|
-
"name": "__NAME_PASCAL__"
|
|
4
|
-
},
|
|
5
|
-
"nav": {
|
|
6
|
-
"home": "Inicio",
|
|
7
|
-
"about": "Acerca de"
|
|
8
|
-
},
|
|
9
|
-
"screens": {
|
|
10
|
-
"home": {
|
|
11
|
-
"welcome": "Bienvenido a __NAME_PASCAL__",
|
|
12
|
-
"message": "Un solo código — web, iOS y Android. Edita features/__NAME__/src/HomeScreen.tsx para empezar."
|
|
13
|
-
},
|
|
14
|
-
"about": {
|
|
15
|
-
"title": "Acerca de",
|
|
16
|
-
"message": "Esta pantalla vive en features/__NAME__ y se conecta a la ruta /about desde apps/__NAME__/routes/about.tsx.",
|
|
17
|
-
"back": "Volver al inicio"
|
|
18
|
-
},
|
|
19
|
-
"contact": {
|
|
20
|
-
"title": "Contacto",
|
|
21
|
-
"name": "Nombre",
|
|
22
|
-
"namePlaceholder": "Tu nombre",
|
|
23
|
-
"message": "Mensaje",
|
|
24
|
-
"messagePlaceholder": "¿Qué quieres decir?",
|
|
25
|
-
"send": "Enviar",
|
|
26
|
-
"required": "Este campo es obligatorio",
|
|
27
|
-
"sent": "Mensaje enviado (demo) — mira la consola."
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* i18next TypeScript type augmentations.
|
|
3
|
-
*
|
|
4
|
-
* Key typing is intentionally loose (t() accepts any string; missing keys fall
|
|
5
|
-
* back at runtime). To restore strict typed keys, add
|
|
6
|
-
* `resources: { common: typeof import("./en/common.json") }` to
|
|
7
|
-
* CustomTypeOptions.
|
|
8
|
-
*/
|
|
9
|
-
import "i18next";
|
|
10
|
-
|
|
11
|
-
declare module "i18next" {
|
|
12
|
-
interface CustomTypeOptions {
|
|
13
|
-
defaultNS: "common";
|
|
14
|
-
returnNull: false;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Supported languages. Add a language by creating `<lng>/common.json` and
|
|
3
|
-
* listing the code here (and in resources.ts for native).
|
|
4
|
-
*/
|
|
5
|
-
export const languages = ["en", "es"] as const;
|
|
6
|
-
|
|
7
|
-
/** Translation namespaces — one JSON file per namespace per language. */
|
|
8
|
-
export const namespaces = ["common"] as const;
|
|
9
|
-
|
|
10
|
-
/** Fallback language when a translation is missing. */
|
|
11
|
-
export const defaultLanguage = "en" as const;
|
|
12
|
-
|
|
13
|
-
/** Namespace used when t() calls do not specify one. */
|
|
14
|
-
export const defaultNamespace = "common" as const;
|
|
15
|
-
|
|
16
|
-
export type Language = (typeof languages)[number];
|
|
17
|
-
export type Namespace = (typeof namespaces)[number];
|
|
18
|
-
|
|
19
|
-
// Re-export framework i18n utilities
|
|
20
|
-
export {
|
|
21
|
-
createI18nConfig,
|
|
22
|
-
detectLanguage,
|
|
23
|
-
getPersistedLanguage,
|
|
24
|
-
persistLanguage,
|
|
25
|
-
} from "@multiplatform.one/i18n";
|
|
26
|
-
export type { I18nConfigOptions } from "@multiplatform.one/i18n";
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@package/i18n",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./index.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./index.ts",
|
|
9
|
-
"./resources": "./resources.ts"
|
|
10
|
-
},
|
|
11
|
-
"scripts": {
|
|
12
|
-
"typecheck": "tsgo --noEmit"
|
|
13
|
-
},
|
|
14
|
-
"dependencies": {
|
|
15
|
-
"@multiplatform.one/i18n": "__MPO_VERSION__"
|
|
16
|
-
},
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"typescript": "~5.9.3"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Static resource map for native (web loads translations through the vite
|
|
2
|
-
// i18next loader instead — see apps/__NAME__/routes/_layout.web.tsx).
|
|
3
|
-
import en from "./en/common.json";
|
|
4
|
-
import es from "./es/common.json";
|
|
5
|
-
|
|
6
|
-
export const resources = {
|
|
7
|
-
en: {
|
|
8
|
-
common: en,
|
|
9
|
-
},
|
|
10
|
-
es: {
|
|
11
|
-
common: es,
|
|
12
|
-
},
|
|
13
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// Framework default brand accent: solid-surface hsla(250) ramps. Replace with
|
|
2
|
-
// your brand color ramps to rebrand the whole app in one place.
|
|
3
|
-
export const accentTheme = {
|
|
4
|
-
darkPalette: [
|
|
5
|
-
"hsla(250, 50%, 35%, 1)",
|
|
6
|
-
"hsla(250, 50%, 38%, 1)",
|
|
7
|
-
"hsla(250, 50%, 41%, 1)",
|
|
8
|
-
"hsla(250, 50%, 43%, 1)",
|
|
9
|
-
"hsla(250, 50%, 46%, 1)",
|
|
10
|
-
"hsla(250, 50%, 49%, 1)",
|
|
11
|
-
"hsla(250, 50%, 52%, 1)",
|
|
12
|
-
"hsla(250, 50%, 54%, 1)",
|
|
13
|
-
"hsla(250, 50%, 57%, 1)",
|
|
14
|
-
"hsla(250, 50%, 60%, 1)",
|
|
15
|
-
"hsla(250, 50%, 90%, 1)",
|
|
16
|
-
"hsla(250, 50%, 95%, 1)",
|
|
17
|
-
],
|
|
18
|
-
lightPalette: [
|
|
19
|
-
"hsla(250, 50%, 95%, 1)",
|
|
20
|
-
"hsla(250, 50%, 95%, 1)",
|
|
21
|
-
"hsla(250, 50%, 65%, 1)",
|
|
22
|
-
"hsla(250, 50%, 62%, 1)",
|
|
23
|
-
"hsla(250, 50%, 59%, 1)",
|
|
24
|
-
"hsla(250, 50%, 57%, 1)",
|
|
25
|
-
"hsla(250, 50%, 54%, 1)",
|
|
26
|
-
"hsla(250, 50%, 51%, 1)",
|
|
27
|
-
"hsla(250, 50%, 48%, 1)",
|
|
28
|
-
"hsla(250, 50%, 46%, 1)",
|
|
29
|
-
"hsla(250, 50%, 43%, 1)",
|
|
30
|
-
"hsla(250, 50%, 40%, 1)",
|
|
31
|
-
],
|
|
32
|
-
};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// Framework default neutral ramps: Radix-mauve-shaped with a slight purple
|
|
2
|
-
// tint (hue 270) harmonizing with the hsla(250) accent. Steps: near-white
|
|
3
|
-
// surfaces (1-2), component/hover (3-5), borders (6-8), solid/muted (9-10),
|
|
4
|
-
// readable text (11-12). Swap these palettes to rebrand.
|
|
5
|
-
export const baseTheme = {
|
|
6
|
-
darkPalette: [
|
|
7
|
-
"hsla(270, 6%, 8.7%, 1)",
|
|
8
|
-
"hsla(270, 6%, 10.5%, 1)",
|
|
9
|
-
"hsla(270, 6%, 13.5%, 1)",
|
|
10
|
-
"hsla(270, 6%, 16%, 1)",
|
|
11
|
-
"hsla(270, 6%, 18.5%, 1)",
|
|
12
|
-
"hsla(270, 6%, 21.5%, 1)",
|
|
13
|
-
"hsla(270, 6%, 25.5%, 1)",
|
|
14
|
-
"hsla(270, 6%, 32%, 1)",
|
|
15
|
-
"hsla(270, 6%, 43%, 1)",
|
|
16
|
-
"hsla(270, 6%, 48%, 1)",
|
|
17
|
-
"hsla(270, 6%, 62.5%, 1)",
|
|
18
|
-
"hsla(270, 6%, 94%, 1)",
|
|
19
|
-
],
|
|
20
|
-
lightPalette: [
|
|
21
|
-
"hsla(270, 6%, 99.5%, 1)",
|
|
22
|
-
"hsla(270, 6%, 98.2%, 1)",
|
|
23
|
-
"hsla(270, 6%, 95.2%, 1)",
|
|
24
|
-
"hsla(270, 6%, 92.5%, 1)",
|
|
25
|
-
"hsla(270, 6%, 90%, 1)",
|
|
26
|
-
"hsla(270, 6%, 87%, 1)",
|
|
27
|
-
"hsla(270, 6%, 82.5%, 1)",
|
|
28
|
-
"hsla(270, 6%, 75%, 1)",
|
|
29
|
-
"hsla(270, 6%, 56.5%, 1)",
|
|
30
|
-
"hsla(270, 6%, 52%, 1)",
|
|
31
|
-
"hsla(270, 6%, 40%, 1)",
|
|
32
|
-
"hsla(270, 6%, 14%, 1)",
|
|
33
|
-
],
|
|
34
|
-
lightShadows: {
|
|
35
|
-
shadow1: "rgba(0,0,0,0.04)",
|
|
36
|
-
shadow2: "rgba(0,0,0,0.08)",
|
|
37
|
-
shadow3: "rgba(0,0,0,0.16)",
|
|
38
|
-
shadow4: "rgba(0,0,0,0.24)",
|
|
39
|
-
shadow5: "rgba(0,0,0,0.32)",
|
|
40
|
-
shadow6: "rgba(0,0,0,0.4)",
|
|
41
|
-
},
|
|
42
|
-
darkShadows: {
|
|
43
|
-
shadow1: "rgba(0,0,0,0.2)",
|
|
44
|
-
shadow2: "rgba(0,0,0,0.3)",
|
|
45
|
-
shadow3: "rgba(0,0,0,0.4)",
|
|
46
|
-
shadow4: "rgba(0,0,0,0.5)",
|
|
47
|
-
shadow5: "rgba(0,0,0,0.6)",
|
|
48
|
-
shadow6: "rgba(0,0,0,0.7)",
|
|
49
|
-
},
|
|
50
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { createFontLoader } from "@multiplatform.one/theme";
|
|
2
|
-
|
|
3
|
-
// Loads the default Inter faces on native (web gets them via CSS). Add custom
|
|
4
|
-
// fonts by listing { family, nativeModule } entries.
|
|
5
|
-
export const { importFonts } = createFontLoader({
|
|
6
|
-
fonts: [],
|
|
7
|
-
inter: true,
|
|
8
|
-
});
|