|
1 | | -import { createSignal, For } from 'solid-js'; |
| 1 | +import { For } from 'solid-js'; |
2 | 2 |
|
3 | 3 | const demos = [ |
4 | 4 | { |
5 | 5 | id: 'demo', |
6 | 6 | title: 'Streaming Demo', |
7 | | - description: 'Watch markdown stream in real-time with syntax highlighting', |
| 7 | + description: 'Watch markdown render in real-time', |
8 | 8 | icon: '⚡', |
9 | | - color: 'bg-blue-500', |
| 9 | + color: 'bg-green-100', |
| 10 | + darkColor: 'dark:bg-green-900', |
10 | 11 | }, |
11 | 12 | { |
12 | 13 | id: 'chat', |
13 | 14 | title: 'Chat Interface', |
14 | | - description: 'Interactive chat with AI-style message streaming', |
| 15 | + description: 'Interactive AI chat with streaming', |
15 | 16 | icon: '💬', |
16 | | - color: 'bg-emerald-500', |
| 17 | + color: 'bg-purple-100', |
| 18 | + darkColor: 'dark:bg-purple-900', |
17 | 19 | }, |
18 | 20 | ]; |
19 | 21 |
|
20 | 22 | const features = [ |
21 | | - { icon: '📝', title: 'Full Markdown', desc: 'Headers, lists, tables' }, |
22 | | - { icon: '🎨', title: 'Syntax Highlighting', desc: '50+ languages' }, |
23 | | - { icon: '📐', title: 'Math Support', desc: 'LaTeX equations' }, |
24 | | - { icon: '🔗', title: 'Interactive Links', desc: 'Tappable URLs' }, |
25 | | - { icon: '🌊', title: 'Stream Ready', desc: 'Token-by-token' }, |
26 | | - { icon: '📱', title: 'Native Views', desc: 'iOS & Android' }, |
27 | | - { icon: '🎯', title: 'Accessibility', desc: 'VoiceOver ready' }, |
28 | | - { icon: '🌙', title: 'Dark Mode', desc: 'Theme support' }, |
29 | | - { icon: '📊', title: 'Tables', desc: 'GFM tables' }, |
30 | | - { icon: '✅', title: 'Task Lists', desc: 'Checkboxes' }, |
| 23 | + 'Stream markdown', |
| 24 | + 'Incomplete tokens', |
| 25 | + 'GFM support', |
| 26 | + 'Code highlighting', |
| 27 | + 'Tables', |
| 28 | + 'Math (LaTeX)', |
| 29 | + 'Images', |
| 30 | + 'Native performance', |
| 31 | + 'Dark mode', |
| 32 | + 'CJK support', |
31 | 33 | ]; |
32 | 34 |
|
| 35 | +const getFeatureRow = (index) => Math.floor(index / 2); |
| 36 | +const getFeatureCol = (index) => index % 2; |
| 37 | + |
33 | 38 | export const Home = (props) => { |
34 | 39 | return ( |
35 | 40 | <page> |
36 | | - <actionbar flat={true} class="bg-slate-50"> |
37 | | - <label text="Streamdown" class="font-bold text-lg" /> |
38 | | - </actionbar> |
| 41 | + <actionbar flat={true} class="bg-slate-50 dark:bg-slate-900" title="nstreamdown"> |
39 | 42 |
|
40 | | - <scrollview class="bg-slate-50"> |
41 | | - <stacklayout class="pb-8"> |
42 | | - {/* Hero Section */} |
43 | | - <stacklayout class="px-6 pt-6 pb-4"> |
44 | | - <label text="@nstudio/nstreamdown" class="text-3xl font-bold text-slate-800" /> |
45 | | - <label |
46 | | - text="Native iOS & Android streaming markdown for NativeScript" |
47 | | - class="text-base text-slate-500 mt-2" |
48 | | - textWrap={true} |
49 | | - /> |
50 | | - </stacklayout> |
| 43 | + </actionbar> |
| 44 | + <gridlayout rows="*" class="bg-slate-50 dark:bg-slate-900"> |
| 45 | + |
| 46 | + {/* Content */} |
| 47 | + <scrollview> |
| 48 | + <stacklayout class="p-4 pt-6"> |
| 49 | + {/* Hero section */} |
| 50 | + <stacklayout class="bg-gradient-to-br from-blue-600 to-purple-700 dark:from-blue-700 dark:to-purple-800 rounded-2xl p-6 mb-6"> |
| 51 | + <label text="Native Markdown Streaming" class="text-xl dark:text-white text-black font-bold text-center leading-[3]" /> |
| 52 | + <label text="Real-time AI streaming with beautiful markdown rendering, powered by NativeScript." class="text-sm text-blue-400 dark:text-blue-200 text-center leading-[3] mt-2" textWrap={true} /> |
| 53 | + </stacklayout> |
| 54 | + |
| 55 | + {/* Demo cards */} |
| 56 | + <label text="Demos" class="text-xs font-semibold text-slate-400 dark:text-slate-500 uppercase tracking-wide mb-3" /> |
51 | 57 |
|
52 | | - {/* Demo Cards */} |
53 | | - <stacklayout class="px-4"> |
54 | 58 | <For each={demos}> |
55 | 59 | {(demo) => ( |
56 | | - <gridlayout |
57 | | - columns="auto, *" |
58 | | - rows="auto, auto" |
59 | | - class="bg-white rounded-2xl p-4 mb-3 shadow-sm" |
60 | | - on:tap={() => props.onNavigate(demo.id)} |
61 | | - > |
62 | | - <label |
63 | | - col="0" |
64 | | - row="0" |
65 | | - rowSpan="2" |
66 | | - text={demo.icon} |
67 | | - class={`text-3xl ${demo.color} w-14 h-14 text-center leading-[56] rounded-xl mr-4`} |
68 | | - /> |
69 | | - <label |
70 | | - col="1" |
71 | | - row="0" |
72 | | - text={demo.title} |
73 | | - class="text-lg font-semibold text-slate-800" |
74 | | - /> |
75 | | - <label |
76 | | - col="1" |
77 | | - row="1" |
78 | | - text={demo.description} |
79 | | - class="text-sm text-slate-500" |
80 | | - textWrap={true} |
81 | | - /> |
82 | | - </gridlayout> |
83 | | - )} |
84 | | - </For> |
85 | | - </stacklayout> |
| 60 | + <stacklayout class="mb-3"> |
| 61 | + <gridlayout columns="48, *, auto" rows="48" class="bg-white dark:bg-slate-800 rounded-xl p-3 shadow-sm" on:tap={() => props.onNavigate(demo.id)}> |
| 62 | + {/* Icon container - vertically centered via GridLayout */} |
| 63 | + <gridlayout col="0" rows="*" columns="*" class={`w-12 h-12 rounded-xl ${demo.color} ${demo.darkColor}`}> |
| 64 | + <label text={demo.icon} class="text-xl text-center" /> |
| 65 | + </gridlayout> |
86 | 66 |
|
87 | | - {/* Features Section */} |
88 | | - <label text="Features" class="text-xl font-bold text-slate-800 px-6 mt-6 mb-3" /> |
| 67 | + {/* Text - use nested GridLayout for vertical centering */} |
| 68 | + <gridlayout col="1" rows="*,auto, auto,*" class="ml-3"> |
| 69 | + <label row="1" text={demo.title} class="text-base font-semibold text-slate-800 dark:text-slate-100 leading-[3]" /> |
| 70 | + <label row="2" text={demo.description} class="text-xs text-slate-500 dark:text-slate-400 leading-[3]" textWrap={true} /> |
| 71 | + </gridlayout> |
89 | 72 |
|
90 | | - <flexboxlayout |
91 | | - flexWrap="wrap" |
92 | | - justifyContent="flex-start" |
93 | | - class="px-4" |
94 | | - > |
95 | | - <For each={features}> |
96 | | - {(feature) => ( |
97 | | - <stacklayout class="w-[30%] bg-white rounded-xl p-3 m-[1.5%] items-center"> |
98 | | - <label text={feature.icon} class="text-2xl mb-1" /> |
99 | | - <label text={feature.title} class="text-xs font-medium text-slate-700 text-center" /> |
100 | | - <label text={feature.desc} class="text-[10] text-slate-400 text-center" /> |
| 73 | + {/* Arrow */} |
| 74 | + <label col="2" text="›" class="text-2xl text-slate-300 dark:text-slate-600 font-light" /> |
| 75 | + </gridlayout> |
101 | 76 | </stacklayout> |
102 | 77 | )} |
103 | 78 | </For> |
104 | | - </flexboxlayout> |
105 | 79 |
|
106 | | - {/* Footer */} |
107 | | - <stacklayout class="items-center mt-8 px-6"> |
108 | | - <label text="Built with ❤️ by @aspect" class="text-sm text-slate-400" /> |
109 | | - <label text="NativeScript + Solid.js" class="text-xs text-slate-300 mt-1" /> |
| 80 | + {/* Features list */} |
| 81 | + <label text="Features" class="text-xs font-semibold text-slate-400 dark:text-slate-500 uppercase tracking-wide mt-6 mb-3" /> |
| 82 | + |
| 83 | + <gridlayout columns="*, *" rows="auto, auto, auto, auto, auto" class="bg-white dark:bg-slate-800 rounded-xl p-4 shadow-sm"> |
| 84 | + <For each={features}> |
| 85 | + {(feature, index) => ( |
| 86 | + <gridlayout row={getFeatureRow(index())} col={getFeatureCol(index())} columns="auto, *" class="p-2"> |
| 87 | + <label col="0" text="✓" class="text-green-500 dark:text-green-400 text-sm mr-2" /> |
| 88 | + <label col="1" text={feature} class="text-sm text-slate-600 dark:text-slate-300 leading-[3]" textWrap={true} /> |
| 89 | + </gridlayout> |
| 90 | + )} |
| 91 | + </For> |
| 92 | + </gridlayout> |
| 93 | + |
| 94 | + {/* Footer */} |
| 95 | + <label text="Inspired by streamdown.ai • Built for NativeScript" class="text-xs text-slate-400 dark:text-slate-500 text-center mt-8 mb-4" /> |
110 | 96 | </stacklayout> |
111 | | - </stacklayout> |
112 | | - </scrollview> |
| 97 | + </scrollview> |
| 98 | + </gridlayout> |
113 | 99 | </page> |
114 | 100 | ); |
115 | 101 | }; |
0 commit comments