create-nix-app 1.0.7 → 1.0.10
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/package.json +1 -1
- package/template-nix-ionic/README.md +52 -10
- package/template-nix-ionic/index.html +2 -1
- package/template-nix-ionic/package.json +4 -4
- package/template-nix-ionic/src/main.ts +22 -9
- package/template-nix-ionic/src/pages/HomePage.ts +31 -0
- package/template-nix-ionic/src/style.css +14 -72
- package/template-nix-ionic/vite.config.ts +0 -3
- package/template-nix-ionic/src/pages/detail-page.ts +0 -80
- package/template-nix-ionic/src/pages/home-page.ts +0 -68
package/package.json
CHANGED
|
@@ -1,19 +1,61 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Nix-Ionic App
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A mobile-first starter template powered by **[Nix.js](https://www.npmjs.com/package/@deijose/nix-js)** + **[Ionic](https://ionicframework.com/)** + **[Capacitor](https://capacitorjs.com/)**.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
Para comenzar a desarrollar:
|
|
5
|
+
## Quick Start
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
8
|
npm install
|
|
11
9
|
npm run dev
|
|
12
10
|
```
|
|
13
11
|
|
|
14
|
-
##
|
|
12
|
+
## Build for Production
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm run build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Deploy to Android
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# First build the web app
|
|
22
|
+
npm run build
|
|
23
|
+
|
|
24
|
+
# Sync with Capacitor
|
|
25
|
+
npx cap sync android
|
|
26
|
+
|
|
27
|
+
# Open Android Studio
|
|
28
|
+
npx cap open android
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Project Structure
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
src/
|
|
35
|
+
├── main.ts # Entry point — Ionic setup & router
|
|
36
|
+
├── style.css # Global styles
|
|
37
|
+
└── pages/
|
|
38
|
+
└── HomePage.ts # Your first page (IonPage)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Modular Loading
|
|
42
|
+
|
|
43
|
+
This template uses **nix-ionic v0.3.0** modular component loading.
|
|
44
|
+
Import only the bundles your app needs in `main.ts`:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { layoutComponents } from "@deijose/nix-ionic/bundles/layout";
|
|
48
|
+
import { formComponents } from "@deijose/nix-ionic/bundles/forms";
|
|
49
|
+
import { overlayComponents } from "@deijose/nix-ionic/bundles/overlays";
|
|
50
|
+
|
|
51
|
+
setupNixIonic({ components: [...layoutComponents, ...formComponents] });
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Available bundles: `layout`, `navigation`, `forms`, `lists`, `feedback`, `buttons`, `overlays`, `all`.
|
|
55
|
+
|
|
56
|
+
## Learn More
|
|
15
57
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
58
|
+
- [Nix.js Docs](https://github.com/DeijoseDevelop/nix-js)
|
|
59
|
+
- [Nix-Ionic on npm](https://www.npmjs.com/package/@deijose/nix-ionic)
|
|
60
|
+
- [Ionic Components](https://ionicframework.com/docs/components)
|
|
61
|
+
- [Capacitor Docs](https://capacitorjs.com/docs)
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<link rel="icon" href="/favicon.ico">
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
+
<script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
|
|
9
|
+
<script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
|
|
8
10
|
<title>Nix.js + Vite TS</title>
|
|
9
|
-
<link rel="stylesheet" href="/src/style.css">
|
|
10
11
|
</head>
|
|
11
12
|
|
|
12
13
|
<body>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "nix-
|
|
3
|
-
"version": "
|
|
2
|
+
"name": "nix-ionic-app",
|
|
3
|
+
"version": "0.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite",
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"@capacitor/android": "^8.2.0",
|
|
12
12
|
"@capacitor/cli": "^8.2.0",
|
|
13
13
|
"@capacitor/core": "^8.2.0",
|
|
14
|
-
"@deijose/nix-ionic": "^0.1
|
|
14
|
+
"@deijose/nix-ionic": "^0.3.1",
|
|
15
15
|
"@deijose/nix-js": "^1.7.7",
|
|
16
16
|
"@ionic/core": "^8.8.1",
|
|
17
|
-
"
|
|
17
|
+
"ionicons": "^8.0.13"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"typescript": "~5.9.3",
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
defineCustomElements();
|
|
3
|
-
|
|
1
|
+
// 1. Core Ionic Styles
|
|
4
2
|
import "@ionic/core/css/core.css";
|
|
5
3
|
import "@ionic/core/css/normalize.css";
|
|
6
4
|
import "@ionic/core/css/structure.css";
|
|
@@ -8,21 +6,36 @@ import "@ionic/core/css/typography.css";
|
|
|
8
6
|
import "@ionic/core/css/padding.css";
|
|
9
7
|
import "@ionic/core/css/flex-utils.css";
|
|
10
8
|
import "@ionic/core/css/display.css";
|
|
9
|
+
import "./style.css";
|
|
11
10
|
|
|
11
|
+
// 2. Framework
|
|
12
12
|
import { NixComponent, html, mount } from "@deijose/nix-js";
|
|
13
|
-
import { IonRouterOutlet } from "@deijose/nix-ionic";
|
|
14
|
-
|
|
15
|
-
import
|
|
13
|
+
import { setupNixIonic, IonRouterOutlet } from "@deijose/nix-ionic";
|
|
14
|
+
|
|
15
|
+
// 3. Modular component bundles — import only what your app needs
|
|
16
|
+
import { layoutComponents } from "@deijose/nix-ionic/bundles/layout";
|
|
17
|
+
import { formComponents } from "@deijose/nix-ionic/bundles/forms";
|
|
18
|
+
import { listComponents } from "@deijose/nix-ionic/bundles/lists";
|
|
19
|
+
|
|
20
|
+
// 4. Pages
|
|
21
|
+
import { HomePage } from "./pages/HomePage";
|
|
22
|
+
|
|
23
|
+
// Register Ionic components
|
|
24
|
+
setupNixIonic({
|
|
25
|
+
components: [...layoutComponents, ...formComponents, ...listComponents],
|
|
26
|
+
});
|
|
16
27
|
|
|
28
|
+
// 5. Router
|
|
17
29
|
const outlet = new IonRouterOutlet([
|
|
18
|
-
{ path: "/",
|
|
19
|
-
{ path: "/detail/:id", component: (ctx) => new DetailPage(ctx) },
|
|
30
|
+
{ path: "/", component: (ctx) => new HomePage(ctx) },
|
|
20
31
|
]);
|
|
21
32
|
|
|
33
|
+
// 6. Root App Component
|
|
22
34
|
class App extends NixComponent {
|
|
23
|
-
render() {
|
|
35
|
+
override render() {
|
|
24
36
|
return html`<ion-app>${outlet}</ion-app>`;
|
|
25
37
|
}
|
|
26
38
|
}
|
|
27
39
|
|
|
40
|
+
// 7. Bootstrap
|
|
28
41
|
mount(new App(), "#app");
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { html } from "@deijose/nix-js";
|
|
2
|
+
import { IonPage } from "@deijose/nix-ionic";
|
|
3
|
+
import type { PageContext } from "@deijose/nix-ionic";
|
|
4
|
+
|
|
5
|
+
export class HomePage extends IonPage {
|
|
6
|
+
constructor(ctx: PageContext) {
|
|
7
|
+
super(ctx.lc);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
override render() {
|
|
11
|
+
return html`
|
|
12
|
+
<ion-header>
|
|
13
|
+
<ion-toolbar color="primary">
|
|
14
|
+
<ion-title>My Nix-Ionic App</ion-title>
|
|
15
|
+
</ion-toolbar>
|
|
16
|
+
</ion-header>
|
|
17
|
+
|
|
18
|
+
<ion-content class="ion-padding">
|
|
19
|
+
<ion-card>
|
|
20
|
+
<ion-card-header>
|
|
21
|
+
<ion-card-title>Welcome to Nix-Ionic 🚀</ion-card-title>
|
|
22
|
+
<ion-card-subtitle>Powered by Nix.js + Ionic + Capacitor</ion-card-subtitle>
|
|
23
|
+
</ion-card-header>
|
|
24
|
+
<ion-card-content>
|
|
25
|
+
<p>Edit <code>src/pages/HomePage.ts</code> to get started.</p>
|
|
26
|
+
</ion-card-content>
|
|
27
|
+
</ion-card>
|
|
28
|
+
</ion-content>
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,79 +1,21 @@
|
|
|
1
|
+
/* App-level styles */
|
|
1
2
|
:root {
|
|
2
|
-
font-family:
|
|
3
|
-
line-height: 1.5;
|
|
4
|
-
font-weight: 400;
|
|
5
|
-
|
|
6
|
-
color-scheme: light dark;
|
|
7
|
-
color: rgba(255, 255, 255, 0.87);
|
|
8
|
-
background-color: #242424;
|
|
9
|
-
|
|
10
|
-
font-synthesis: none;
|
|
11
|
-
text-rendering: optimizeLegibility;
|
|
12
|
-
-webkit-font-smoothing: antialiased;
|
|
13
|
-
-moz-osx-font-smoothing: grayscale;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
body {
|
|
17
|
-
margin: 0;
|
|
18
|
-
display: flex;
|
|
19
|
-
place-items: center;
|
|
20
|
-
min-width: 320px;
|
|
21
|
-
min-height: 100vh;
|
|
3
|
+
--ion-font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Roboto", sans-serif;
|
|
22
4
|
}
|
|
23
5
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
margin: 0 auto;
|
|
27
|
-
padding: 2rem;
|
|
28
|
-
text-align: center;
|
|
6
|
+
* {
|
|
7
|
+
box-sizing: border-box;
|
|
29
8
|
}
|
|
30
9
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
background: linear-gradient(45deg, #646cff, #60efff);
|
|
35
|
-
-webkit-background-clip: text;
|
|
36
|
-
background-clip: text;
|
|
37
|
-
-webkit-text-fill-color: transparent;
|
|
38
|
-
display: flex;
|
|
39
|
-
align-items: center;
|
|
40
|
-
justify-content: center;
|
|
41
|
-
gap: 16px;
|
|
10
|
+
ion-card p {
|
|
11
|
+
color: var(--ion-color-medium);
|
|
12
|
+
margin-top: 8px;
|
|
42
13
|
}
|
|
43
14
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
border-radius: 8px;
|
|
52
|
-
border: 1px solid transparent;
|
|
53
|
-
padding: 0.6em 1.2em;
|
|
54
|
-
font-size: 1em;
|
|
55
|
-
font-weight: 500;
|
|
56
|
-
font-family: inherit;
|
|
57
|
-
background-color: #1a1a1a;
|
|
58
|
-
cursor: pointer;
|
|
59
|
-
transition: border-color 0.25s;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
button:hover {
|
|
63
|
-
border-color: #646cff;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
button:focus,
|
|
67
|
-
button:focus-visible {
|
|
68
|
-
outline: 4px auto -webkit-focus-ring-color;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@media (prefers-color-scheme: light) {
|
|
72
|
-
:root {
|
|
73
|
-
color: #213547;
|
|
74
|
-
background-color: #ffffff;
|
|
75
|
-
}
|
|
76
|
-
button {
|
|
77
|
-
background-color: #f9f9f9;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
15
|
+
ion-card code {
|
|
16
|
+
font-family: monospace;
|
|
17
|
+
background: var(--ion-color-light);
|
|
18
|
+
padding: 2px 6px;
|
|
19
|
+
border-radius: 4px;
|
|
20
|
+
font-size: 0.9em;
|
|
21
|
+
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { html, signal, batch } from "@deijose/nix-js";
|
|
2
|
-
import type { NixTemplate } from "@deijose/nix-js";
|
|
3
|
-
import { IonPage, IonBackButton } from "@deijose/nix-ionic";
|
|
4
|
-
import type { PageContext } from "@deijose/nix-ionic";
|
|
5
|
-
|
|
6
|
-
interface Post { id: number; title: string; body: string; userId: number; }
|
|
7
|
-
|
|
8
|
-
export class DetailPage extends IonPage {
|
|
9
|
-
private post = signal<Post | null>(null);
|
|
10
|
-
private loading = signal(true);
|
|
11
|
-
private elapsed = signal(0);
|
|
12
|
-
private _timer = 0;
|
|
13
|
-
private _id: string;
|
|
14
|
-
|
|
15
|
-
constructor({ lc, params }: PageContext) {
|
|
16
|
-
super(lc);
|
|
17
|
-
this._id = params["id"] ?? "1";
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
override onInit(): void {
|
|
21
|
-
super.onInit();
|
|
22
|
-
this._loadPost(this._id);
|
|
23
|
-
console.log("DETAIL INIT (Solo se debe ver una vez por instancia)");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
override ionViewWillEnter(): void {
|
|
27
|
-
this.elapsed.value = 0;
|
|
28
|
-
this._timer = setInterval(
|
|
29
|
-
() => this.elapsed.update((n) => n + 1), 1000
|
|
30
|
-
) as unknown as number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
override ionViewWillLeave(): void {
|
|
34
|
-
clearInterval(this._timer);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private async _loadPost(id: string): Promise<void> {
|
|
38
|
-
this.loading.value = true;
|
|
39
|
-
try {
|
|
40
|
-
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
|
|
41
|
-
const data = await res.json() as Post;
|
|
42
|
-
batch(() => { this.post.value = data; this.loading.value = false; });
|
|
43
|
-
} catch { this.loading.value = false; }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
override render(): NixTemplate {
|
|
47
|
-
return html`
|
|
48
|
-
<ion-header>
|
|
49
|
-
<ion-toolbar color="primary">
|
|
50
|
-
<ion-buttons slot="start">
|
|
51
|
-
${IonBackButton()}
|
|
52
|
-
</ion-buttons>
|
|
53
|
-
<ion-title>Detalle</ion-title>
|
|
54
|
-
</ion-toolbar>
|
|
55
|
-
</ion-header>
|
|
56
|
-
<ion-content class="ion-padding">
|
|
57
|
-
${() => this.loading.value
|
|
58
|
-
? html`<ion-spinner name="crescent"></ion-spinner>`
|
|
59
|
-
: html`
|
|
60
|
-
<ion-card>
|
|
61
|
-
<ion-card-header>
|
|
62
|
-
<ion-card-title>${() => this.post.value?.title ?? ""}</ion-card-title>
|
|
63
|
-
<ion-card-subtitle>
|
|
64
|
-
Post #${() => this.post.value?.id ?? ""}
|
|
65
|
-
· Usuario ${() => this.post.value?.userId ?? ""}
|
|
66
|
-
</ion-card-subtitle>
|
|
67
|
-
</ion-card-header>
|
|
68
|
-
<ion-card-content>
|
|
69
|
-
${() => this.post.value?.body ?? ""}
|
|
70
|
-
<p style="margin-top:12px;color:var(--ion-color-medium);">
|
|
71
|
-
⏱ ${() => this.elapsed.value}s en vista
|
|
72
|
-
</p>
|
|
73
|
-
</ion-card-content>
|
|
74
|
-
</ion-card>
|
|
75
|
-
`
|
|
76
|
-
}
|
|
77
|
-
</ion-content>
|
|
78
|
-
`;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { html, signal, batch } from "@deijose/nix-js";
|
|
2
|
-
import type { NixTemplate } from "@deijose/nix-js";
|
|
3
|
-
import { IonPage, useRouter } from "@deijose/nix-ionic";
|
|
4
|
-
import type { PageContext } from "@deijose/nix-ionic";
|
|
5
|
-
|
|
6
|
-
interface Post { id: number; title: string; body: string; }
|
|
7
|
-
|
|
8
|
-
export class HomePage extends IonPage {
|
|
9
|
-
private posts = signal<Post[]>([]);
|
|
10
|
-
private loading = signal(false);
|
|
11
|
-
private visits = signal(0);
|
|
12
|
-
|
|
13
|
-
constructor({ lc }: PageContext) { super(lc); }
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
override onInit(): void {
|
|
17
|
-
super.onInit();
|
|
18
|
-
this.visits.update((n) => n + 1);
|
|
19
|
-
this._loadPosts();
|
|
20
|
-
|
|
21
|
-
console.log("HOME INIT (Solo se debe ver una vez por instancia)");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
private async _loadPosts(): Promise<void> {
|
|
25
|
-
this.loading.value = true;
|
|
26
|
-
try {
|
|
27
|
-
const res = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");
|
|
28
|
-
const data = await res.json() as Post[];
|
|
29
|
-
batch(() => { this.posts.value = data; this.loading.value = false; });
|
|
30
|
-
} catch { this.loading.value = false; }
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
override render(): NixTemplate {
|
|
34
|
-
const router = useRouter();
|
|
35
|
-
return html`
|
|
36
|
-
<ion-header>
|
|
37
|
-
<ion-toolbar color="primary">
|
|
38
|
-
<ion-title>Home</ion-title>
|
|
39
|
-
</ion-toolbar>
|
|
40
|
-
</ion-header>
|
|
41
|
-
<ion-content class="ion-padding">
|
|
42
|
-
<ion-note color="medium" style="display:block;margin-bottom:12px;">
|
|
43
|
-
Visitas: <strong>${() => this.visits.value}</strong>
|
|
44
|
-
</ion-note>
|
|
45
|
-
${() => this.loading.value
|
|
46
|
-
? html`<ion-spinner name="crescent"></ion-spinner>`
|
|
47
|
-
: html`
|
|
48
|
-
<ion-list>
|
|
49
|
-
${() => this.posts.value.map((post) => html`
|
|
50
|
-
<ion-item button detail
|
|
51
|
-
@click=${() => router.navigate(`/detail/${post.id}`)}>
|
|
52
|
-
<ion-label>
|
|
53
|
-
<h2>${post.title}</h2>
|
|
54
|
-
<p>${post.body.slice(0, 60)}…</p>
|
|
55
|
-
</ion-label>
|
|
56
|
-
</ion-item>
|
|
57
|
-
`)}
|
|
58
|
-
</ion-list>
|
|
59
|
-
`
|
|
60
|
-
}
|
|
61
|
-
<ion-button expand="block" style="margin-top:16px;"
|
|
62
|
-
@click=${() => router.navigate("/profile")}>
|
|
63
|
-
Ver perfil
|
|
64
|
-
</ion-button>
|
|
65
|
-
</ion-content>
|
|
66
|
-
`;
|
|
67
|
-
}
|
|
68
|
-
}
|