@even-toolkit/create-even-app 1.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 (126) hide show
  1. package/index.js +159 -0
  2. package/package.json +28 -0
  3. package/templates/chat/README.md +27 -0
  4. package/templates/chat/index.html +12 -0
  5. package/templates/chat/package.json +34 -0
  6. package/templates/chat/src/App.tsx +61 -0
  7. package/templates/chat/src/app.css +54 -0
  8. package/templates/chat/src/contexts/ChatContext.tsx +99 -0
  9. package/templates/chat/src/glass/AppGlasses.tsx +70 -0
  10. package/templates/chat/src/glass/screens/home.ts +24 -0
  11. package/templates/chat/src/glass/selectors.ts +9 -0
  12. package/templates/chat/src/glass/shared.ts +8 -0
  13. package/templates/chat/src/glass/splash.ts +25 -0
  14. package/templates/chat/src/main.tsx +13 -0
  15. package/templates/chat/src/screens/ChatScreen.tsx +69 -0
  16. package/templates/chat/src/screens/Settings.tsx +88 -0
  17. package/templates/chat/src/types.ts +13 -0
  18. package/templates/chat/src/vite-env.d.ts +1 -0
  19. package/templates/chat/template.json +7 -0
  20. package/templates/chat/tsconfig.json +20 -0
  21. package/templates/chat/tsconfig.node.json +13 -0
  22. package/templates/chat/vite.config.ts +12 -0
  23. package/templates/dashboard/README.md +17 -0
  24. package/templates/dashboard/index.html +12 -0
  25. package/templates/dashboard/package.json +34 -0
  26. package/templates/dashboard/src/App.tsx +27 -0
  27. package/templates/dashboard/src/app.css +54 -0
  28. package/templates/dashboard/src/glass/AppGlasses.tsx +53 -0
  29. package/templates/dashboard/src/glass/screens/home.ts +23 -0
  30. package/templates/dashboard/src/glass/selectors.ts +9 -0
  31. package/templates/dashboard/src/glass/shared.ts +8 -0
  32. package/templates/dashboard/src/glass/splash.ts +22 -0
  33. package/templates/dashboard/src/main.tsx +13 -0
  34. package/templates/dashboard/src/screens/ChartsScreen.tsx +99 -0
  35. package/templates/dashboard/src/screens/OverviewScreen.tsx +102 -0
  36. package/templates/dashboard/src/screens/SettingsScreen.tsx +60 -0
  37. package/templates/dashboard/src/vite-env.d.ts +1 -0
  38. package/templates/dashboard/template.json +7 -0
  39. package/templates/dashboard/tsconfig.json +20 -0
  40. package/templates/dashboard/tsconfig.node.json +13 -0
  41. package/templates/dashboard/vite.config.ts +12 -0
  42. package/templates/media/README.md +27 -0
  43. package/templates/media/index.html +12 -0
  44. package/templates/media/package.json +34 -0
  45. package/templates/media/src/App.tsx +24 -0
  46. package/templates/media/src/app.css +54 -0
  47. package/templates/media/src/contexts/MediaContext.tsx +108 -0
  48. package/templates/media/src/glass/AppGlasses.tsx +59 -0
  49. package/templates/media/src/glass/screens/home.ts +24 -0
  50. package/templates/media/src/glass/selectors.ts +9 -0
  51. package/templates/media/src/glass/shared.ts +8 -0
  52. package/templates/media/src/glass/splash.ts +25 -0
  53. package/templates/media/src/layouts/shell.tsx +39 -0
  54. package/templates/media/src/main.tsx +13 -0
  55. package/templates/media/src/screens/AudioScreen.tsx +78 -0
  56. package/templates/media/src/screens/GalleryScreen.tsx +98 -0
  57. package/templates/media/src/screens/Settings.tsx +86 -0
  58. package/templates/media/src/screens/UploadScreen.tsx +95 -0
  59. package/templates/media/src/types.ts +29 -0
  60. package/templates/media/src/vite-env.d.ts +1 -0
  61. package/templates/media/template.json +7 -0
  62. package/templates/media/tsconfig.json +20 -0
  63. package/templates/media/tsconfig.node.json +13 -0
  64. package/templates/media/vite.config.ts +12 -0
  65. package/templates/minimal/README.md +27 -0
  66. package/templates/minimal/index.html +12 -0
  67. package/templates/minimal/package.json +34 -0
  68. package/templates/minimal/src/App.tsx +50 -0
  69. package/templates/minimal/src/app.css +54 -0
  70. package/templates/minimal/src/glass/AppGlasses.tsx +54 -0
  71. package/templates/minimal/src/glass/screens/home.ts +24 -0
  72. package/templates/minimal/src/glass/selectors.ts +9 -0
  73. package/templates/minimal/src/glass/shared.ts +8 -0
  74. package/templates/minimal/src/glass/splash.ts +25 -0
  75. package/templates/minimal/src/main.tsx +13 -0
  76. package/templates/minimal/src/vite-env.d.ts +1 -0
  77. package/templates/minimal/template.json +7 -0
  78. package/templates/minimal/tsconfig.json +20 -0
  79. package/templates/minimal/tsconfig.node.json +13 -0
  80. package/templates/minimal/vite.config.ts +12 -0
  81. package/templates/notes/README.md +27 -0
  82. package/templates/notes/index.html +12 -0
  83. package/templates/notes/package.json +34 -0
  84. package/templates/notes/src/App.tsx +25 -0
  85. package/templates/notes/src/app.css +54 -0
  86. package/templates/notes/src/contexts/NotesContext.tsx +140 -0
  87. package/templates/notes/src/glass/AppGlasses.tsx +58 -0
  88. package/templates/notes/src/glass/screens/home.ts +24 -0
  89. package/templates/notes/src/glass/selectors.ts +9 -0
  90. package/templates/notes/src/glass/shared.ts +8 -0
  91. package/templates/notes/src/glass/splash.ts +24 -0
  92. package/templates/notes/src/layouts/shell.tsx +36 -0
  93. package/templates/notes/src/main.tsx +13 -0
  94. package/templates/notes/src/screens/NoteDetail.tsx +104 -0
  95. package/templates/notes/src/screens/NoteForm.tsx +84 -0
  96. package/templates/notes/src/screens/NoteList.tsx +108 -0
  97. package/templates/notes/src/screens/Settings.tsx +88 -0
  98. package/templates/notes/src/types.ts +14 -0
  99. package/templates/notes/src/vite-env.d.ts +1 -0
  100. package/templates/notes/template.json +7 -0
  101. package/templates/notes/tsconfig.json +20 -0
  102. package/templates/notes/tsconfig.node.json +13 -0
  103. package/templates/notes/vite.config.ts +12 -0
  104. package/templates/tracker/README.md +27 -0
  105. package/templates/tracker/index.html +12 -0
  106. package/templates/tracker/package.json +34 -0
  107. package/templates/tracker/src/App.tsx +24 -0
  108. package/templates/tracker/src/app.css +54 -0
  109. package/templates/tracker/src/contexts/TrackerContext.tsx +193 -0
  110. package/templates/tracker/src/glass/AppGlasses.tsx +64 -0
  111. package/templates/tracker/src/glass/screens/home.ts +24 -0
  112. package/templates/tracker/src/glass/selectors.ts +9 -0
  113. package/templates/tracker/src/glass/shared.ts +8 -0
  114. package/templates/tracker/src/glass/splash.ts +24 -0
  115. package/templates/tracker/src/layouts/shell.tsx +37 -0
  116. package/templates/tracker/src/main.tsx +13 -0
  117. package/templates/tracker/src/screens/HistoryScreen.tsx +106 -0
  118. package/templates/tracker/src/screens/NewEntryScreen.tsx +135 -0
  119. package/templates/tracker/src/screens/Settings.tsx +135 -0
  120. package/templates/tracker/src/screens/TodayScreen.tsx +147 -0
  121. package/templates/tracker/src/types.ts +34 -0
  122. package/templates/tracker/src/vite-env.d.ts +1 -0
  123. package/templates/tracker/template.json +7 -0
  124. package/templates/tracker/tsconfig.json +20 -0
  125. package/templates/tracker/tsconfig.node.json +13 -0
  126. package/templates/tracker/vite.config.ts +12 -0
@@ -0,0 +1,135 @@
1
+ import { useState } from 'react'
2
+ import { SettingsGroup, Toggle, ListItem, Card, Button, Divider, Input, useDrawerHeader } from 'even-toolkit/web'
3
+ import { useTracker } from '../contexts/TrackerContext'
4
+
5
+ export function Settings() {
6
+ const { goals, setGoals, entries, showCompletionBadge, setShowCompletionBadge } = useTracker()
7
+ const [confirmClear, setConfirmClear] = useState(false)
8
+
9
+ const [waterGoal, setWaterGoal] = useState(String(goals.water))
10
+ const [stepsGoal, setStepsGoal] = useState(String(goals.steps))
11
+ const [focusGoal, setFocusGoal] = useState(String(goals.focus))
12
+
13
+ useDrawerHeader({ title: 'Settings', backTo: '/' })
14
+
15
+ function handleSaveGoals() {
16
+ const w = parseInt(waterGoal, 10)
17
+ const s = parseInt(stepsGoal, 10)
18
+ const f = parseInt(focusGoal, 10)
19
+ if (!isNaN(w) && !isNaN(s) && !isNaN(f) && w > 0 && s > 0 && f > 0) {
20
+ setGoals({ water: w, steps: s, focus: f })
21
+ }
22
+ }
23
+
24
+ function handleExport() {
25
+ const data = JSON.stringify(entries, null, 2)
26
+ const blob = new Blob([data], { type: 'application/json' })
27
+ const url = URL.createObjectURL(blob)
28
+ const a = document.createElement('a')
29
+ a.href = url
30
+ a.download = `tracker-export-${Date.now()}.json`
31
+ a.click()
32
+ URL.revokeObjectURL(url)
33
+ }
34
+
35
+ function handleClearAll() {
36
+ if (!confirmClear) {
37
+ setConfirmClear(true)
38
+ return
39
+ }
40
+ localStorage.removeItem('{{APP_NAME}}-entries')
41
+ localStorage.removeItem('{{APP_NAME}}-goals')
42
+ localStorage.removeItem('{{APP_NAME}}-settings')
43
+ window.location.reload()
44
+ }
45
+
46
+ return (
47
+ <main className="px-3 pt-4 pb-8 space-y-6">
48
+ <SettingsGroup label="Goals">
49
+ <Card className="p-4 space-y-3">
50
+ <div className="space-y-1.5">
51
+ <label className="text-[11px] tracking-[-0.11px] text-text-dim block">Water (glasses per day)</label>
52
+ <Input
53
+ type="number"
54
+ value={waterGoal}
55
+ onChange={(e) => setWaterGoal(e.target.value)}
56
+ />
57
+ </div>
58
+ <div className="space-y-1.5">
59
+ <label className="text-[11px] tracking-[-0.11px] text-text-dim block">Steps (per day)</label>
60
+ <Input
61
+ type="number"
62
+ value={stepsGoal}
63
+ onChange={(e) => setStepsGoal(e.target.value)}
64
+ />
65
+ </div>
66
+ <div className="space-y-1.5">
67
+ <label className="text-[11px] tracking-[-0.11px] text-text-dim block">Focus (minutes per day)</label>
68
+ <Input
69
+ type="number"
70
+ value={focusGoal}
71
+ onChange={(e) => setFocusGoal(e.target.value)}
72
+ />
73
+ </div>
74
+ <Button size="sm" onClick={handleSaveGoals}>
75
+ Save Goals
76
+ </Button>
77
+ </Card>
78
+ </SettingsGroup>
79
+
80
+ <SettingsGroup label="Display">
81
+ <Card className="p-4">
82
+ <div className="flex items-center justify-between">
83
+ <div>
84
+ <p className="text-[15px] tracking-[-0.15px] text-text">Completion Badge</p>
85
+ <p className="text-[11px] tracking-[-0.11px] text-text-dim mt-0.5">
86
+ Show daily completion percentage in history
87
+ </p>
88
+ </div>
89
+ <Toggle checked={showCompletionBadge} onChange={setShowCompletionBadge} />
90
+ </div>
91
+ </Card>
92
+ </SettingsGroup>
93
+
94
+ <SettingsGroup label="Data">
95
+ <Card className="divide-y divide-border">
96
+ <ListItem
97
+ title="Export Data"
98
+ subtitle={`Export all ${entries.length} entries as JSON`}
99
+ onPress={handleExport}
100
+ />
101
+ <div>
102
+ <ListItem
103
+ title={confirmClear ? 'Tap again to confirm' : 'Clear All Data'}
104
+ subtitle="Permanently delete all entries and reset goals"
105
+ onPress={handleClearAll}
106
+ />
107
+ {confirmClear && (
108
+ <div className="px-4 pb-3">
109
+ <Button
110
+ variant="ghost"
111
+ size="sm"
112
+ className="w-full"
113
+ onClick={() => setConfirmClear(false)}
114
+ >
115
+ Cancel
116
+ </Button>
117
+ </div>
118
+ )}
119
+ </div>
120
+ </Card>
121
+ </SettingsGroup>
122
+
123
+ <SettingsGroup label="About">
124
+ <Card className="p-4 space-y-1.5">
125
+ <p className="text-[15px] tracking-[-0.15px] text-text">{{DISPLAY_NAME}}</p>
126
+ <p className="text-[13px] tracking-[-0.13px] text-text-dim">Version 1.0.0</p>
127
+ <Divider className="my-2" />
128
+ <p className="text-[11px] tracking-[-0.11px] text-text-dim">
129
+ An activity and habit tracker for Even Realities G2 smart glasses. All data is stored locally in your browser.
130
+ </p>
131
+ </Card>
132
+ </SettingsGroup>
133
+ </main>
134
+ )
135
+ }
@@ -0,0 +1,147 @@
1
+ import { useState, useEffect, useCallback } from 'react'
2
+ import { useNavigate } from 'react-router'
3
+ import { Card, Button, Progress, StatusProgress, TimerRing, StatGrid, ScreenHeader, useDrawerHeader } from 'even-toolkit/web'
4
+ import { IcPlus } from 'even-toolkit/web/icons/svg-icons'
5
+ import { useTracker } from '../contexts/TrackerContext'
6
+
7
+ function formatPercent(value: number, target: number): string {
8
+ return `${Math.round((value / target) * 100)}%`
9
+ }
10
+
11
+ export function TodayScreen() {
12
+ const navigate = useNavigate()
13
+ const { goals, getTodayTotal } = useTracker()
14
+
15
+ const waterTotal = getTodayTotal('Water')
16
+ const stepsTotal = getTodayTotal('Steps')
17
+ const focusTotal = getTodayTotal('Focus')
18
+
19
+ // Focus timer state
20
+ const [timerActive, setTimerActive] = useState(false)
21
+ const [timerRemaining, setTimerRemaining] = useState(25 * 60) // 25 min default
22
+
23
+ useEffect(() => {
24
+ if (!timerActive || timerRemaining <= 0) return
25
+ const interval = setInterval(() => {
26
+ setTimerRemaining((prev) => {
27
+ if (prev <= 1) {
28
+ setTimerActive(false)
29
+ return 0
30
+ }
31
+ return prev - 1
32
+ })
33
+ }, 1000)
34
+ return () => clearInterval(interval)
35
+ }, [timerActive, timerRemaining])
36
+
37
+ const toggleTimer = useCallback(() => {
38
+ if (timerRemaining <= 0) {
39
+ setTimerRemaining(25 * 60)
40
+ setTimerActive(true)
41
+ } else {
42
+ setTimerActive((prev) => !prev)
43
+ }
44
+ }, [timerRemaining])
45
+
46
+ // Routine steps
47
+ const hour = new Date().getHours()
48
+ const routineSteps = [
49
+ { label: 'Morning', status: hour >= 9 ? 'complete' as const : hour >= 6 ? 'in-progress' as const : 'waiting' as const },
50
+ { label: 'Work', status: hour >= 17 ? 'complete' as const : hour >= 9 ? 'in-progress' as const : 'waiting' as const },
51
+ { label: 'Exercise', status: stepsTotal >= goals.steps ? 'complete' as const : hour >= 17 ? 'in-progress' as const : 'waiting' as const },
52
+ { label: 'Evening', status: hour >= 21 ? 'complete' as const : hour >= 19 ? 'in-progress' as const : 'waiting' as const },
53
+ ]
54
+
55
+ useDrawerHeader({
56
+ right: (
57
+ <Button variant="ghost" size="icon" onClick={() => navigate('/new')}>
58
+ <IcPlus width={20} height={20} />
59
+ </Button>
60
+ ),
61
+ })
62
+
63
+ return (
64
+ <main className="px-3 pt-4 pb-8 space-y-3">
65
+ <ScreenHeader
66
+ title="Today"
67
+ subtitle={new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric' })}
68
+ />
69
+
70
+ {/* Daily Goals Progress */}
71
+ <Card className="p-4 space-y-3">
72
+ <p className="text-[15px] tracking-[-0.15px] text-text">Daily Goals</p>
73
+
74
+ <div className="space-y-3">
75
+ <div className="space-y-1.5">
76
+ <div className="flex items-center justify-between">
77
+ <span className="text-[13px] tracking-[-0.13px] text-text">Water</span>
78
+ <span className="text-[13px] tracking-[-0.13px] text-text-dim">
79
+ {waterTotal}/{goals.water} glasses
80
+ </span>
81
+ </div>
82
+ <Progress value={(waterTotal / goals.water) * 100} />
83
+ </div>
84
+
85
+ <div className="space-y-1.5">
86
+ <div className="flex items-center justify-between">
87
+ <span className="text-[13px] tracking-[-0.13px] text-text">Steps</span>
88
+ <span className="text-[13px] tracking-[-0.13px] text-text-dim">
89
+ {stepsTotal.toLocaleString()}/{goals.steps.toLocaleString()}
90
+ </span>
91
+ </div>
92
+ <Progress value={(stepsTotal / goals.steps) * 100} />
93
+ </div>
94
+
95
+ <div className="space-y-1.5">
96
+ <div className="flex items-center justify-between">
97
+ <span className="text-[13px] tracking-[-0.13px] text-text">Focus</span>
98
+ <span className="text-[13px] tracking-[-0.13px] text-text-dim">
99
+ {focusTotal}/{goals.focus} min
100
+ </span>
101
+ </div>
102
+ <Progress value={(focusTotal / goals.focus) * 100} />
103
+ </div>
104
+ </div>
105
+ </Card>
106
+
107
+ {/* Daily Routine */}
108
+ <Card className="p-4 space-y-3">
109
+ <p className="text-[15px] tracking-[-0.15px] text-text">Daily Routine</p>
110
+ <StatusProgress steps={routineSteps} />
111
+ </Card>
112
+
113
+ {/* Focus Timer */}
114
+ <Card className="p-4 space-y-3">
115
+ <p className="text-[15px] tracking-[-0.15px] text-text">Focus Timer</p>
116
+ <div className="flex flex-col items-center gap-3">
117
+ <TimerRing
118
+ remaining={timerRemaining}
119
+ total={25 * 60}
120
+ size={140}
121
+ strokeWidth={6}
122
+ />
123
+ <Button
124
+ size="sm"
125
+ variant={timerActive ? 'secondary' : 'default'}
126
+ onClick={toggleTimer}
127
+ >
128
+ {timerRemaining <= 0 ? 'Restart' : timerActive ? 'Pause' : 'Start Focus'}
129
+ </Button>
130
+ </div>
131
+ </Card>
132
+
133
+ {/* Today's Stats */}
134
+ <Card className="p-4 space-y-3">
135
+ <p className="text-[15px] tracking-[-0.15px] text-text">Stats</p>
136
+ <StatGrid
137
+ columns={3}
138
+ stats={[
139
+ { label: 'Water', value: formatPercent(waterTotal, goals.water) },
140
+ { label: 'Steps', value: formatPercent(stepsTotal, goals.steps) },
141
+ { label: 'Focus', value: formatPercent(focusTotal, goals.focus) },
142
+ ]}
143
+ />
144
+ </Card>
145
+ </main>
146
+ )
147
+ }
@@ -0,0 +1,34 @@
1
+ export type ActivityType = 'Water' | 'Steps' | 'Focus'
2
+
3
+ export interface TrackerEntry {
4
+ id: string
5
+ activity: ActivityType
6
+ value: number
7
+ note: string
8
+ timestamp: number
9
+ }
10
+
11
+ export interface DayRecord {
12
+ date: string // YYYY-MM-DD
13
+ entries: TrackerEntry[]
14
+ }
15
+
16
+ export interface GoalTargets {
17
+ water: number // glasses
18
+ steps: number // steps
19
+ focus: number // minutes
20
+ }
21
+
22
+ export const ACTIVITIES: ActivityType[] = ['Water', 'Steps', 'Focus']
23
+
24
+ export const DEFAULT_GOALS: GoalTargets = {
25
+ water: 8,
26
+ steps: 10000,
27
+ focus: 60,
28
+ }
29
+
30
+ export const ACTIVITY_UNITS: Record<ActivityType, string> = {
31
+ Water: 'glasses',
32
+ Steps: 'steps',
33
+ Focus: 'min',
34
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "tracker",
3
+ "displayName": "Activity Tracker",
4
+ "description": "Activity and habit tracker with daily goals, history calendar, and focus timer — built for G2 smart glasses",
5
+ "tags": ["tracker", "habits", "health"],
6
+ "components": ["DrawerShell", "ScreenHeader", "Card", "Button", "Progress", "StatusProgress", "TimerRing", "StatGrid", "Calendar", "Timeline", "StepIndicator", "Select", "Slider", "Input", "Textarea", "Badge", "SettingsGroup", "Toggle", "Divider", "ListItem"]
7
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "jsx": "react-jsx",
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "skipLibCheck": true,
11
+ "esModuleInterop": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "isolatedModules": true,
15
+ "baseUrl": ".",
16
+ "paths": { "@/*": ["./src/*"] }
17
+ },
18
+ "include": ["src"],
19
+ "references": [{ "path": "./tsconfig.node.json" }]
20
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "types": ["node"],
8
+ "composite": true,
9
+ "noEmit": false,
10
+ "skipLibCheck": true
11
+ },
12
+ "include": ["vite.config.ts"]
13
+ }
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import tailwindcss from '@tailwindcss/vite'
4
+ import path from 'path'
5
+
6
+ export default defineConfig({
7
+ plugins: [react(), tailwindcss()],
8
+ resolve: {
9
+ alias: { '@': path.resolve(__dirname, './src') },
10
+ dedupe: ['react', 'react-dom', 'react-router', '@evenrealities/even_hub_sdk', '@jappyjan/even-better-sdk', 'upng-js'],
11
+ },
12
+ })