helfy-create 0.0.5 → 0.1.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.
Files changed (44) hide show
  1. package/README.md +49 -38
  2. package/bin/create-helfy.js +8 -0
  3. package/package.json +31 -31
  4. package/template/declaration.d.ts +10 -8
  5. package/template/package-lock.json +6981 -7000
  6. package/template/package.json +29 -30
  7. package/template/rspack.config.js +76 -0
  8. package/template/src/App.hf +20 -0
  9. package/template/src/App.ts +5 -0
  10. package/template/src/context/ThemeContext.ts +18 -0
  11. package/template/src/pages/AboutPage.hf +12 -0
  12. package/template/src/pages/AboutPage.ts +5 -0
  13. package/template/src/pages/CounterPage.hf +13 -0
  14. package/template/src/pages/CounterPage.ts +15 -0
  15. package/template/src/pages/HomePage.hf +17 -0
  16. package/template/src/pages/HomePage.ts +5 -0
  17. package/template/src/pages/_router.hf +21 -0
  18. package/template/src/pages/_router.ts +5 -0
  19. package/template/src/pages/{_routes.tsx → _routes.ts} +10 -10
  20. package/template/src/pages/layouts/MainLayout.hf +24 -0
  21. package/template/src/pages/layouts/MainLayout.ts +5 -0
  22. package/template/src/widgets/Footer/Footer.hf +5 -0
  23. package/template/src/widgets/Footer/Footer.ts +5 -0
  24. package/template/src/widgets/Header/Header.hf +15 -0
  25. package/template/src/widgets/Header/Header.ts +11 -0
  26. package/template/src/widgets/Navbar/Navbar.hf +14 -0
  27. package/template/src/widgets/Navbar/Navbar.ts +11 -0
  28. package/template/src/widgets/NotFound/NotFound.hf +14 -0
  29. package/template/src/widgets/NotFound/NotFound.ts +12 -0
  30. package/template/src/widgets/ThemeToggle/ThemeToggle.hf +16 -0
  31. package/template/src/widgets/ThemeToggle/ThemeToggle.ts +12 -0
  32. package/template/src/widgets/navLinks.ts +5 -0
  33. package/template/tsconfig.json +0 -2
  34. package/template/src/App.tsx +0 -26
  35. package/template/src/context/ThemeContext.tsx +0 -60
  36. package/template/src/pages/AboutPage.tsx +0 -18
  37. package/template/src/pages/CounterPage.tsx +0 -17
  38. package/template/src/pages/HomePage.tsx +0 -22
  39. package/template/src/pages/_router.tsx +0 -15
  40. package/template/src/pages/layouts/MainLayout.tsx +0 -29
  41. package/template/src/widgets/Footer/Footer.tsx +0 -8
  42. package/template/src/widgets/Header/Header.tsx +0 -34
  43. package/template/src/widgets/Navbar/Navbar.tsx +0 -29
  44. package/template/src/widgets/NotFound/NotFound.tsx +0 -31
@@ -1,30 +1,29 @@
1
- {
2
- "name": "{{PROJECT_NAME}}",
3
- "version": "0.1.0",
4
- "private": true,
5
- "scripts": {
6
- "dev": "cross-env NODE_ENV=development rspack serve",
7
- "build": "cross-env NODE_ENV=production rspack build"
8
- },
9
- "dependencies": {
10
- "@helfy/helfy": "^0.0.9"
11
- },
12
- "devDependencies": {
13
- "@babel/core": "^7.20.0",
14
- "@babel/plugin-proposal-class-properties": "^7.18.6",
15
- "@babel/plugin-proposal-decorators": "^7.21.0",
16
- "@babel/plugin-proposal-private-methods": "^7.18.6",
17
- "@babel/plugin-proposal-private-property-in-object": "^7.21.0",
18
- "@babel/preset-env": "^7.20.0",
19
- "@babel/preset-react": "^7.18.6",
20
- "@babel/preset-typescript": "^7.21.0",
21
- "@helfy/helfy-ts-plugin": "^0.0.1",
22
- "babel-loader": "^9.1.2",
23
- "babel-plugin-transform-typescript-metadata": "^0.4.0",
24
- "cross-env": "^7.0.3",
25
- "css-loader": "^6.7.3",
26
- "typescript": "^5.9.3",
27
- "@rspack/cli": "^1.3.0",
28
- "@rspack/core": "^1.3.0"
29
- }
30
- }
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "cross-env NODE_ENV=development rspack serve",
7
+ "build": "cross-env NODE_ENV=production rspack build"
8
+ },
9
+ "dependencies": {
10
+ "@helfy/helfy": "^0.1.2"
11
+ },
12
+ "devDependencies": {
13
+ "@babel/core": "^7.20.0",
14
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
15
+ "@babel/plugin-proposal-decorators": "^7.21.0",
16
+ "@babel/plugin-proposal-private-methods": "^7.18.6",
17
+ "@babel/plugin-proposal-private-property-in-object": "^7.21.0",
18
+ "@babel/preset-env": "^7.20.0",
19
+ "@babel/preset-react": "^7.18.6",
20
+ "@babel/preset-typescript": "^7.21.0",
21
+ "@rspack/cli": "^1.3.0",
22
+ "@rspack/core": "^1.3.0",
23
+ "babel-loader": "^9.1.2",
24
+ "babel-plugin-transform-typescript-metadata": "^0.4.0",
25
+ "cross-env": "^7.0.3",
26
+ "css-loader": "^6.7.3",
27
+ "typescript": "^5.9.3"
28
+ }
29
+ }
@@ -0,0 +1,76 @@
1
+ const path = require('path');
2
+ const { rspack } = require('@rspack/core');
3
+
4
+ const isDev = process.env.NODE_ENV === 'development';
5
+
6
+ const paths = {
7
+ src: path.resolve(__dirname, 'src'),
8
+ dist: path.resolve(__dirname, 'dist'),
9
+ };
10
+
11
+ module.exports = {
12
+ context: paths.src,
13
+ mode: isDev ? 'development' : 'production',
14
+ entry: './index.ts',
15
+ watchOptions: isDev
16
+ ? { ignored: ['**/node_modules/**', '**/.helfy/**'] }
17
+ : {},
18
+ devServer: {
19
+ hot: true,
20
+ port: 3000,
21
+ static: { directory: paths.src },
22
+ compress: true,
23
+ historyApiFallback: true,
24
+ },
25
+ output: {
26
+ filename: 'bundle.js',
27
+ path: paths.dist,
28
+ publicPath: '/',
29
+ clean: true,
30
+ },
31
+ resolve: {
32
+ modules: ['src', 'node_modules'],
33
+ extensions: ['.ts', '.js', '.hf', '.css'],
34
+ alias: {
35
+ '@': path.resolve(__dirname, 'src'),
36
+ '@context': path.resolve(__dirname, 'src/context'),
37
+ '@pages': path.resolve(__dirname, 'src/pages'),
38
+ '@widgets': path.resolve(__dirname, 'src/widgets'),
39
+ },
40
+ },
41
+ plugins: [
42
+ new rspack.HtmlRspackPlugin({
43
+ template: './index.html',
44
+ minify: !isDev,
45
+ }),
46
+ new rspack.CssExtractRspackPlugin({
47
+ filename: `css/${isDev ? '[name]' : '[contenthash:8]_[id]'}.css`,
48
+ ignoreOrder: true,
49
+ }),
50
+ ],
51
+ module: {
52
+ rules: [
53
+ {
54
+ test: /\.css$/,
55
+ type: 'javascript/auto',
56
+ use: [
57
+ rspack.CssExtractRspackPlugin.loader,
58
+ { loader: 'css-loader', options: { importLoaders: 1 } },
59
+ ],
60
+ },
61
+ {
62
+ test: /\.hf$/,
63
+ exclude: /node_modules/,
64
+ use: [
65
+ 'babel-loader',
66
+ require.resolve('@helfy/helfy/compiler/hf-loader'),
67
+ ],
68
+ },
69
+ {
70
+ test: /\.(ts|js)$/,
71
+ exclude: /node_modules/,
72
+ use: 'babel-loader',
73
+ },
74
+ ],
75
+ },
76
+ };
@@ -0,0 +1,20 @@
1
+ import type { App } from "./App";
2
+ import { ThemeContext } from "@context/ThemeContext";
3
+ import { MainLayout } from "@pages/layouts/MainLayout";
4
+ import { Header } from "@widgets/Header/Header";
5
+ import { NavBar } from "@widgets/Navbar/Navbar";
6
+ import { Footer } from "@widgets/Footer/Footer";
7
+ import { AppRouter } from "@pages/_router";
8
+
9
+ @template<App>() {
10
+ <ThemeContext>
11
+ <div class="app">
12
+ <MainLayout>
13
+ @slot.header -> <Header />
14
+ @slot.sidebar -> <NavBar />
15
+ @slot.content -> <AppRouter />
16
+ @slot.footer -> <Footer />
17
+ </MainLayout>
18
+ </div>
19
+ </ThemeContext>
20
+ }
@@ -0,0 +1,5 @@
1
+ import { View } from "@helfy/helfy";
2
+ import template from "./App.hf";
3
+
4
+ @View({ template })
5
+ export class App {}
@@ -0,0 +1,18 @@
1
+ import { Context, state, effect } from "@helfy/helfy";
2
+
3
+ export type TThemeMode = "light" | "dark";
4
+
5
+ @Context
6
+ export class ThemeContext {
7
+ @state mode: TThemeMode = "dark";
8
+
9
+ toggle = () => {
10
+ this.mode = this.mode === "dark" ? "light" : "dark";
11
+ };
12
+
13
+ /** Keeps class="dark" on <html> in sync with the mode. */
14
+ @effect
15
+ syncToDom() {
16
+ document.documentElement.classList.toggle("dark", this.mode === "dark");
17
+ }
18
+ }
@@ -0,0 +1,12 @@
1
+ import type { AboutPage } from "./AboutPage";
2
+
3
+ @template<AboutPage>() {
4
+ <div class="page">
5
+ <h1>About</h1>
6
+ <p>This is a Helfy application with routing, slots, a theme context and a lazily loaded page.</p>
7
+ <p>
8
+ This page is a separate chunk loaded on the first visit — see <code>lazy()</code> in
9
+ <code>src/pages/_routes.ts</code>.
10
+ </p>
11
+ </div>
12
+ }
@@ -0,0 +1,5 @@
1
+ import { View } from "@helfy/helfy";
2
+ import template from "./AboutPage.hf";
3
+
4
+ @View({ template })
5
+ export class AboutPage {}
@@ -0,0 +1,13 @@
1
+ import type { CounterPage } from "./CounterPage";
2
+
3
+ @template<CounterPage>() {
4
+ <div class="page">
5
+ <h1>Counter</h1>
6
+ <p>Count: <strong>{this.count}</strong> ({this.parity})</p>
7
+ <button class="btn" onclick={this.increment}>Increment</button>
8
+ <button class="btn" onclick={this.decrement}>Decrement</button>
9
+ @if (this.count >= 10) {
10
+ <p>That's a lot of clicks!</p>
11
+ }
12
+ </div>
13
+ }
@@ -0,0 +1,15 @@
1
+ import { View, state, computed } from "@helfy/helfy";
2
+ import template from "./CounterPage.hf";
3
+
4
+ @View({ template })
5
+ export class CounterPage {
6
+ @state count = 0;
7
+
8
+ @computed
9
+ get parity() {
10
+ return this.count % 2 === 0 ? "even" : "odd";
11
+ }
12
+
13
+ increment = () => this.count++;
14
+ decrement = () => this.count--;
15
+ }
@@ -0,0 +1,17 @@
1
+ import type { HomePage } from "./HomePage";
2
+
3
+ @template<HomePage>() {
4
+ <div class="page">
5
+ <h1>Welcome to Helfy</h1>
6
+ <p>Helfy is a TypeScript UI framework with decorators, .hf templates and fine-grained reactivity.</p>
7
+ <p>
8
+ Edit <code>src/pages/HomePage.hf</code> and save the file — changes will appear automatically.
9
+ </p>
10
+ <h2>Quick start</h2>
11
+ <p>
12
+ A component is a class with <code>@View</code> (<code>HomePage.ts</code>), its markup lives in the
13
+ <code>.hf</code> template next to it. Open the Counter page to see reactivity in action and toggle the theme in
14
+ the top-right corner.
15
+ </p>
16
+ </div>
17
+ }
@@ -0,0 +1,5 @@
1
+ import { View } from "@helfy/helfy";
2
+ import template from "./HomePage.hf";
3
+
4
+ @View({ template })
5
+ export class HomePage {}
@@ -0,0 +1,21 @@
1
+ import type { AppRouter } from "./_router";
2
+ import { RouterView } from "@helfy/helfy";
3
+ import { NotFound } from "@widgets/NotFound/NotFound";
4
+
5
+ @template<AppRouter>() {
6
+ @safe {
7
+ <RouterView>
8
+ @slot.notFound({ pathname }) {
9
+ <NotFound pathname={pathname} />
10
+ }
11
+ </RouterView>
12
+ } @wait {
13
+ <p class="page">Loading…</p>
14
+ } @fail (error, retry) {
15
+ <section class="page" role="alert">
16
+ <h2>Something went wrong</h2>
17
+ <p>{error instanceof Error ? error.message : String(error)}</p>
18
+ <button type="button" class="btn" onclick={retry}>Try again</button>
19
+ </section>
20
+ }
21
+ }
@@ -0,0 +1,5 @@
1
+ import { View } from "@helfy/helfy";
2
+ import template from "./_router.hf";
3
+
4
+ @View({ template })
5
+ export class AppRouter {}
@@ -1,10 +1,10 @@
1
- import type { RouteConfig } from "@helfy/helfy";
2
- import { HomePage } from "./HomePage";
3
- import { CounterPage } from "./CounterPage";
4
- import { AboutPage } from "./AboutPage";
5
-
6
- export const routes: RouteConfig[] = [
7
- { path: "/", component: HomePage },
8
- { path: "/counter", component: CounterPage },
9
- { path: "/about", component: AboutPage },
10
- ];
1
+ import { lazy, type RouteConfig } from "@helfy/helfy";
2
+ import { HomePage } from "./HomePage";
3
+ import { CounterPage } from "./CounterPage";
4
+
5
+ export const routes: RouteConfig[] = [
6
+ { path: "/", component: HomePage },
7
+ { path: "/counter", component: CounterPage },
8
+ // A separate chunk, loaded on the first visit.
9
+ { path: "/about", component: lazy(() => import("./AboutPage").then((m) => m.AboutPage)) },
10
+ ];
@@ -0,0 +1,24 @@
1
+ import type { MainLayout } from "./MainLayout";
2
+
3
+ @template<MainLayout>() {
4
+ <div class="layout">
5
+ <header class="header">
6
+ @slot:header()
7
+ </header>
8
+ <div class="layout__body">
9
+ <aside class="sidebar">
10
+ @slot:sidebar()
11
+ </aside>
12
+ <main class="main">
13
+ <div class="main__content">
14
+ @slot:content()
15
+ </div>
16
+ </main>
17
+ </div>
18
+ <footer class="footer">
19
+ @slot:footer() fallback {
20
+ <span>© 2026</span>
21
+ }
22
+ </footer>
23
+ </div>
24
+ }
@@ -0,0 +1,5 @@
1
+ import { View } from "@helfy/helfy";
2
+ import template from "./MainLayout.hf";
3
+
4
+ @View({ template })
5
+ export class MainLayout {}
@@ -0,0 +1,5 @@
1
+ import type { Footer } from "./Footer";
2
+
3
+ @template<Footer>() {
4
+ <span>Powered by Helfy — © 2026</span>
5
+ }
@@ -0,0 +1,5 @@
1
+ import { View } from "@helfy/helfy";
2
+ import template from "./Footer.hf";
3
+
4
+ @View({ template })
5
+ export class Footer {}
@@ -0,0 +1,15 @@
1
+ import type { Header } from "./Header";
2
+ import { Link } from "@helfy/helfy";
3
+ import { ThemeToggle } from "@widgets/ThemeToggle/ThemeToggle";
4
+
5
+ @template<Header>() {
6
+ <div class="header__inner">
7
+ <Link to="/" label="Helfy" class="header__logo" />
8
+ <nav class="nav">
9
+ @for (link of this.links; track link.to) {
10
+ <Link to={link.to} label={link.label} class={this.pathname === link.to ? "nav-link--active" : ""} />
11
+ }
12
+ </nav>
13
+ <ThemeToggle />
14
+ </div>
15
+ }
@@ -0,0 +1,11 @@
1
+ import { View, path } from "@helfy/helfy";
2
+ import { NAV_LINKS } from "@widgets/navLinks";
3
+ import template from "./Header.hf";
4
+
5
+ @View({ template })
6
+ export class Header {
7
+ @path()
8
+ pathname?: string;
9
+
10
+ links = NAV_LINKS;
11
+ }
@@ -0,0 +1,14 @@
1
+ import type { NavBar } from "./Navbar";
2
+ import { Link } from "@helfy/helfy";
3
+
4
+ @template<NavBar>() {
5
+ <nav class="sidebar-nav">
6
+ @for (link of this.links; track link.to) {
7
+ <Link
8
+ to={link.to}
9
+ label={link.label}
10
+ class={this.pathname === link.to ? "nav-link nav-link--active" : "nav-link"}
11
+ />
12
+ }
13
+ </nav>
14
+ }
@@ -0,0 +1,11 @@
1
+ import { View, path } from "@helfy/helfy";
2
+ import { NAV_LINKS } from "@widgets/navLinks";
3
+ import template from "./Navbar.hf";
4
+
5
+ @View({ template })
6
+ export class NavBar {
7
+ @path()
8
+ pathname?: string;
9
+
10
+ links = NAV_LINKS;
11
+ }
@@ -0,0 +1,14 @@
1
+ import type { NotFound } from "./NotFound";
2
+ import { Link } from "@helfy/helfy";
3
+
4
+ @template<NotFound>() {
5
+ <section class="not-found">
6
+ <div class="not-found__code">404</div>
7
+ <h1 class="not-found__title">Oops! Page not found</h1>
8
+ <p class="not-found__text">The requested address does not exist or has been moved.</p>
9
+ @if (this.props.pathname) {
10
+ <p class="not-found__path">{this.props.pathname}</p>
11
+ }
12
+ <Link to="/" label="Back to home" class="btn btn--primary" />
13
+ </section>
14
+ }
@@ -0,0 +1,12 @@
1
+ import { View } from "@helfy/helfy";
2
+ import template from "./NotFound.hf";
3
+
4
+ export interface Props {
5
+ pathname?: string;
6
+ }
7
+
8
+ /** Custom 404 page — overrides the RouterView fallback. */
9
+ @View({ template })
10
+ export class NotFound {
11
+ constructor(readonly props: Props = {}) {}
12
+ }
@@ -0,0 +1,16 @@
1
+ import type { ThemeToggle } from "./ThemeToggle";
2
+
3
+ @template<ThemeToggle>() {
4
+ <button
5
+ type="button"
6
+ class="theme-toggle"
7
+ onclick={() => this.toggle()}
8
+ aria-label={this.mode === "dark" ? "Switch to light theme" : "Switch to dark theme"}
9
+ >
10
+ @if (this.mode === "dark") {
11
+ <span>Light</span>
12
+ } @else {
13
+ <span>Dark</span>
14
+ }
15
+ </button>
16
+ }
@@ -0,0 +1,12 @@
1
+ import { View, useCtx } from "@helfy/helfy";
2
+ import { ThemeContext } from "@context/ThemeContext";
3
+ import template from "./ThemeToggle.hf";
4
+
5
+ @View({ template })
6
+ export class ThemeToggle {
7
+ @useCtx(ThemeContext, "toggle")
8
+ toggle!: ThemeContext["toggle"];
9
+
10
+ @useCtx(ThemeContext, "mode")
11
+ mode!: ThemeContext["mode"];
12
+ }
@@ -0,0 +1,5 @@
1
+ export const NAV_LINKS = [
2
+ { to: "/", label: "Home" },
3
+ { to: "/counter", label: "Counter" },
4
+ { to: "/about", label: "About" },
5
+ ];
@@ -7,10 +7,8 @@
7
7
  "noEmit": true,
8
8
  "resolveJsonModule": true,
9
9
  "skipLibCheck": true,
10
- "jsx": "preserve",
11
10
  "experimentalDecorators": true,
12
11
  "emitDecoratorMetadata": true,
13
- "plugins": [{ "name": "@helfy/helfy-ts-plugin" }],
14
12
  "paths": {
15
13
  "@context/*": ["./context/*"],
16
14
  "@pages/*": ["./pages/*"],
@@ -1,26 +0,0 @@
1
- import { View } from "@helfy/helfy";
2
- import { ThemeContext, ThemeSync } from "@context/ThemeContext";
3
- import { MainLayout } from "@pages/layouts/MainLayout";
4
- import { Header } from "@widgets/Header/Header";
5
- import { NavBar } from "@widgets/Navbar/Navbar";
6
- import { Footer } from "@widgets/Footer/Footer";
7
- import { AppRouter } from "@pages/_router";
8
-
9
- @View
10
- export class App {
11
- render() {
12
- return (
13
- <ThemeContext>
14
- <ThemeSync />
15
- <div class="app">
16
- <MainLayout>
17
- @slot.header() {<Header />}
18
- @slot.sidebar() {<NavBar />}
19
- @slot.content() {<AppRouter />}
20
- @slot.footer() {<Footer />}
21
- </MainLayout>
22
- </div>
23
- </ThemeContext>
24
- );
25
- }
26
- }
@@ -1,60 +0,0 @@
1
- import { View, Context, state, useCtx, computed, effect } from "@helfy/helfy";
2
-
3
- export type TThemeMode = "light" | "dark";
4
-
5
- @Context
6
- export class ThemeContext {
7
- @state mode: TThemeMode = "dark";
8
-
9
- @state toggle = () => {
10
- this.mode = this.mode === "dark" ? "light" : "dark";
11
- };
12
-
13
- @effect
14
- syncToDom() {
15
- document.documentElement.classList.toggle("dark", this.mode === "dark");
16
- }
17
- }
18
-
19
- @View
20
- export class ThemeSync {
21
- @useCtx(ThemeContext)
22
- private theme!: ThemeContext;
23
-
24
- onMount() {
25
- document.documentElement.classList.toggle("dark", this.theme.mode === "dark");
26
- }
27
-
28
- render() {
29
- document.documentElement.classList.toggle("dark", this.theme.mode === "dark");
30
- return <span class="hidden" aria-hidden="true"></span>;
31
- }
32
- }
33
-
34
- @View
35
- export class ThemeToggle {
36
- @useCtx(ThemeContext, "toggle")
37
- private toggle!: ThemeContext["toggle"];
38
-
39
- @useCtx(ThemeContext, "mode")
40
- private mode!: ThemeContext["mode"];
41
-
42
- render() {
43
- const isDark = this.mode === "dark";
44
- return (
45
- <button
46
- type="button"
47
- class="theme-toggle"
48
- onclick={this.toggle}
49
- title={isDark ? "Light theme" : "Dark theme"}
50
- aria-label={isDark ? "Switch to light theme" : "Switch to dark theme"}
51
- >
52
- {isDark ? (
53
- <span>Светлая</span>
54
- ) : (
55
- <span>Тёмная</span>
56
- )}
57
- </button>
58
- );
59
- }
60
- }
@@ -1,18 +0,0 @@
1
- import { View } from "@helfy/helfy";
2
-
3
- @View
4
- export class AboutPage {
5
- render() {
6
- return (
7
- <div class="page">
8
- <h1>About</h1>
9
- <p>
10
- This is a Helfy application with routing, slots, and theme context.
11
- </p>
12
- <p>
13
- Helfy is a declarative framework with decorators, reactive state, and built-in TypeScript support.
14
- </p>
15
- </div>
16
- );
17
- }
18
- }
@@ -1,17 +0,0 @@
1
- import { View, state } from "@helfy/helfy";
2
-
3
- @View
4
- export class CounterPage {
5
- @state private count = 0;
6
-
7
- render() {
8
- return (
9
- <div class="page">
10
- <h1>Counter</h1>
11
- <p>Count: <strong>{this.count}</strong></p>
12
- <button class="btn" onclick={() => this.count++}>Increment</button>
13
- <button class="btn" onclick={() => this.count--}>Decrement</button>
14
- </div>
15
- );
16
- }
17
- }
@@ -1,22 +0,0 @@
1
- import { View } from "@helfy/helfy";
2
-
3
- @View
4
- export class HomePage {
5
- render() {
6
- return (
7
- <div class="page">
8
- <h1>Welcome to Helfy</h1>
9
- <p>
10
- Welcome to Helfy — a modern TypeScript framework for web applications.
11
- </p>
12
- <p>
13
- Edit <code>src/App.tsx</code> and save the file — changes will appear automatically.
14
- </p>
15
- <h2>Quick Start</h2>
16
- <p>
17
- Use the sidebar for navigation. Try the Counter page to see reactivity in action and toggle the theme in the top-right corner.
18
- </p>
19
- </div>
20
- );
21
- }
22
- }
@@ -1,15 +0,0 @@
1
- import { RouterView, View } from "@helfy/helfy";
2
- import { NotFound } from "@widgets/NotFound/NotFound";
3
-
4
- @View
5
- export class AppRouter {
6
- render() {
7
- return (
8
- <RouterView>
9
- @slot.notFound({ pathname }) {
10
- <NotFound pathname={pathname} />
11
- }
12
- </RouterView>
13
- );
14
- }
15
- }