Skip to content

Commit 930a2ba

Browse files
committed
feat: solidjs improvements
1 parent c910104 commit 930a2ba

10 files changed

Lines changed: 659 additions & 216 deletions

File tree

apps/demo-solid/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/demo-solid/src/components/ChatDemo.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ export const ChatDemo = (props) => {
250250
return (
251251
<page>
252252
<actionbar flat={true} class="bg-slate-50" title="Chat Demo">
253-
<navigationbutton text="" android={{ systemIcon: 'ic_menu_back' }} on:tap={props.onBack} />
253+
<actionitem position="left">
254+
<label text="Back" class="font-medium px-2" on:tap={props.onBack} />
255+
</actionitem>
254256
</actionbar>
255257

256258
<gridlayout rows="*, auto" class="bg-slate-100">
Lines changed: 67 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,101 @@
1-
import { createSignal, For } from 'solid-js';
1+
import { For } from 'solid-js';
22

33
const demos = [
44
{
55
id: 'demo',
66
title: 'Streaming Demo',
7-
description: 'Watch markdown stream in real-time with syntax highlighting',
7+
description: 'Watch markdown render in real-time',
88
icon: '⚡',
9-
color: 'bg-blue-500',
9+
color: 'bg-green-100',
10+
darkColor: 'dark:bg-green-900',
1011
},
1112
{
1213
id: 'chat',
1314
title: 'Chat Interface',
14-
description: 'Interactive chat with AI-style message streaming',
15+
description: 'Interactive AI chat with streaming',
1516
icon: '💬',
16-
color: 'bg-emerald-500',
17+
color: 'bg-purple-100',
18+
darkColor: 'dark:bg-purple-900',
1719
},
1820
];
1921

2022
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',
3133
];
3234

35+
const getFeatureRow = (index) => Math.floor(index / 2);
36+
const getFeatureCol = (index) => index % 2;
37+
3338
export const Home = (props) => {
3439
return (
3540
<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">
3942

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" />
5157

52-
{/* Demo Cards */}
53-
<stacklayout class="px-4">
5458
<For each={demos}>
5559
{(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>
8666

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>
8972

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>
10176
</stacklayout>
10277
)}
10378
</For>
104-
</flexboxlayout>
10579

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" />
11096
</stacklayout>
111-
</stacklayout>
112-
</scrollview>
97+
</scrollview>
98+
</gridlayout>
11399
</page>
114100
);
115101
};

apps/demo-solid/src/components/StreamdownDemo.jsx

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createSignal, onCleanup } from 'solid-js';
2-
import { isIOS } from '@nativescript/core';
2+
import { isIOS, ScrollView } from '@nativescript/core';
33
import { Streamdown } from '@nstudio/nstreamdown/solid';
44

55
const DEMO_MARKDOWN = `# NativeScript Streamdown 🚀
@@ -112,6 +112,7 @@ export const StreamdownDemo = (props) => {
112112
let streamIndex = 0;
113113
let streamInterval = null;
114114
let startTime = 0;
115+
let scrollViewRef = null;
115116

116117
const config = () => ({
117118
mode: streamingMode(),
@@ -126,6 +127,14 @@ export const StreamdownDemo = (props) => {
126127
}
127128
});
128129

130+
const scrollToBottom = () => {
131+
if (scrollViewRef) {
132+
setTimeout(() => {
133+
scrollViewRef.scrollToVerticalOffset(scrollViewRef.scrollableHeight, false);
134+
}, 10);
135+
}
136+
};
137+
129138
const updateStats = (content) => {
130139
setCharCount(content.length.toString());
131140
setTokenCount(Math.floor(content.length / 4).toString());
@@ -151,6 +160,7 @@ export const StreamdownDemo = (props) => {
151160
setCurrentContent(newContent);
152161
updateStats(newContent);
153162
streamIndex += chunksToProcess;
163+
scrollToBottom();
154164
} else {
155165
stopStreaming();
156166
}
@@ -185,11 +195,15 @@ export const StreamdownDemo = (props) => {
185195
return (
186196
<page>
187197
<actionbar flat={true} class="bg-slate-50" title="Streaming Demo">
188-
<navigationbutton text="" android={{ systemIcon: 'ic_menu_back' }} on:tap={props.onBack} />
189-
<actionitem ios={{ position: 'right' }} on:tap={toggleStreaming}>
190-
{isIOS && isStreaming() && <image src="sys://stop.fill" class="w-5 h-5" />}
191-
{isIOS && !isStreaming() && <image src="sys://play.fill" class="w-5 h-5" />}
192-
{!isIOS && <label text={isStreaming() ? 'Stop' : 'Start'} class="text-blue-600 font-medium px-2" />}
198+
<actionitem position="left">
199+
200+
<label text="Back" class=" font-medium px-2" on:tap={props.onBack} />
201+
202+
</actionitem>
203+
<actionitem position="right">
204+
{isIOS && isStreaming() && <image col="2" src="sys://stop.fill" class="w-5 h-5" on:tap={toggleStreaming} />}
205+
{isIOS && !isStreaming() && <image col="2" src="sys://play.fill" class="w-5 h-5" on:tap={toggleStreaming} />}
206+
{!isIOS && <label col="2" text={isStreaming() ? 'Stop' : 'Start'} class="text-blue-600 font-medium px-2" on:tap={toggleStreaming} />}
193207
</actionitem>
194208
</actionbar>
195209

@@ -211,7 +225,7 @@ export const StreamdownDemo = (props) => {
211225
</gridlayout>
212226

213227
{/* Streamdown content */}
214-
<scrollview row="1" class="mt-3">
228+
<scrollview row="1" class="mt-3" ref={(el) => (scrollViewRef = el)}>
215229
<stacklayout class="mx-4 mb-20 bg-white rounded-xl p-4 shadow-sm">
216230
<Streamdown content={currentContent()} config={config()} />
217231
</stacklayout>

packages/nstreamdown/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131
"email": "oss@nstudio.io"
3232
},
3333
"bugs": {
34-
"url": "https://github.com/nstudio/streamdown/issues"
34+
"url": "https://github.com/nstudio/nstreamdown/issues"
3535
},
3636
"license": "Apache-2.0",
37-
"homepage": "https://github.com/nstudio/streamdown",
37+
"homepage": "https://github.com/nstudio/nstreamdown",
3838
"readmeFilename": "README.md",
3939
"bootstrapper": "@nativescript/plugin-seed",
4040
"peerDependencies": {

0 commit comments

Comments
 (0)