Skip to content

Commit da0fcb3

Browse files
committed
demo ui tweaks
1 parent fc5e723 commit da0fcb3

5 files changed

Lines changed: 90 additions & 82 deletions

File tree

examples/build.md

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -385,22 +385,23 @@ Ionic + Capacitor notes:
385385
386386
### Section Order (top to bottom)
387387
388-
1. **App Section** (App ID input, guidance text, consent required toggle, logged-in state, login/logout actions)
389-
2. **Push Section** (Push subscription ID, push enabled toggle, permission state, auto-prompt on startup)
390-
3. **Send Push Notification Section** (Simple, With Image, and Custom notification actions)
391-
4. **In-App Messaging Section** (IAM paused toggle and lifecycle log visibility)
392-
5. **Send In-App Message Section** (Top Banner, Bottom Banner, Center Modal, Full Screen trigger actions)
393-
6. **Aliases Section** (Add, Add Multiple, Remove, read-only key/value list)
394-
7. **Emails Section** (Add/Remove with list display, collapsible behavior for longer lists)
395-
8. **SMS Section** (Add/Remove with list display, collapsible behavior for longer lists)
396-
9. **Tags Section** (Add, Add Multiple, Remove Selected)
397-
10. **Outcome Events Section** (Send Outcome flow with outcome type selection)
398-
11. **Triggers Section** (Add, Add Multiple, Remove Selected, Clear All - IN MEMORY ONLY)
399-
12. **Track Event Section** (Track event with JSON validation for properties)
400-
13. **Location Section** (Location Shared toggle and Prompt Location action)
401-
14. **Next Page/Activity Button**
402-
403-
### Prompt 2.1 - App Section
388+
1. **App Section** (App ID input, guidance text, consent required toggle)
389+
2. **User Section** (Logged-in state, login/logout actions)
390+
3. **Push Section** (Push subscription ID, push enabled toggle, permission state, auto-prompt on startup)
391+
4. **Send Push Notification Section** (Simple, With Image, and Custom notification actions)
392+
5. **In-App Messaging Section** (IAM paused toggle and lifecycle log visibility)
393+
6. **Send In-App Message Section** (Top Banner, Bottom Banner, Center Modal, Full Screen trigger actions)
394+
7. **Aliases Section** (Add, Add Multiple, Remove, read-only key/value list)
395+
8. **Emails Section** (Add/Remove with list display, collapsible behavior for longer lists)
396+
9. **SMS Section** (Add/Remove with list display, collapsible behavior for longer lists)
397+
10. **Tags Section** (Add, Add Multiple, Remove Selected)
398+
11. **Outcome Events Section** (Send Outcome flow with outcome type selection)
399+
12. **Triggers Section** (Add, Add Multiple, Remove Selected, Clear All - IN MEMORY ONLY)
400+
13. **Track Event Section** (Track event with JSON validation for properties)
401+
14. **Location Section** (Location Shared toggle and Prompt Location action)
402+
15. **Next Page/Activity Button**
403+
404+
### Prompt 2.1a - App Section
404405
405406
App Section layout:
406407
@@ -423,7 +424,11 @@ App Section layout:
423424
- Separated from the above toggle by a horizontal divider
424425
- NOT a blocking overlay — user can interact with app regardless of state
425426
426-
4. User status card (always visible, ABOVE the login/logout buttons):
427+
### Prompt 2.1b - User Section
428+
429+
User Section layout (separate section card titled "User", placed after App Section):
430+
431+
1. User status card (always visible, ABOVE the login/logout buttons):
427432
- Card with two rows separated by a divider
428433
- Row 1: `Status` label on the left, value on the right
429434
- Row 2: `External ID` label on the left, value on the right
@@ -434,12 +439,12 @@ App Section layout:
434439
- Status shows `Logged In` with success color styling
435440
- External ID shows the actual external user ID
436441
437-
5. `LOGIN USER` button:
442+
2. `LOGIN USER` button:
438443
- Shows `LOGIN USER` when no user is logged in
439444
- Shows `SWITCH USER` when a user is logged in
440445
- Opens modal with empty `External User Id` field
441446
442-
6. `LOGOUT USER` button (only visible when a user is logged in)
447+
3. `LOGOUT USER` button (only visible when a user is logged in)
443448
444449
### Prompt 2.2 - Push Section
445450

examples/demo/src/components/LogView.css

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
position: sticky;
33
top: var(--demo-header-height, 84px);
44
z-index: 20;
5-
background: #1a1b1e;
6-
color: #c9d0db;
5+
background: var(--os-log-background);
76
}
87

98
.logview-header {
@@ -22,19 +21,20 @@
2221

2322
.logview-count {
2423
font-size: var(--font-size-label-small);
25-
color: #9e9e9e;
24+
color: var(--os-grey-500);
25+
margin-right: auto;
2626
}
2727

2828
.logview-header .icon-btn {
2929
font-size: 18px;
30-
color: #9e9e9e;
30+
color: var(--os-grey-500);
3131
}
3232

3333
.logview-body {
3434
height: 100px;
3535
overflow-x: auto;
3636
overflow-y: auto;
37-
padding: 0 12px 10px;
37+
padding: 0 12px 4px;
3838
}
3939

4040
.logview-row {
@@ -48,25 +48,26 @@
4848
}
4949

5050
.log-time {
51-
color: #676e7b;
51+
color: var(--os-log-timestamp);
5252
}
5353

5454
.log-level {
5555
font-weight: 700;
5656
}
5757

58-
.log-level-d { color: #82aaff; }
59-
.log-level-i { color: #c3e88d; }
60-
.log-level-w { color: #ffcb6b; }
61-
.log-level-e { color: #ff5370; }
58+
.log-level-d { color: var(--os-log-debug); }
59+
.log-level-i { color: var(--os-log-info); }
60+
.log-level-w { color: var(--os-log-warn); }
61+
.log-level-e { color: var(--os-log-error); }
6262

6363
.log-text {
6464
color: #fff;
6565
}
6666

6767
.logview-empty {
68-
color: #9e9e9e;
68+
color: var(--os-grey-500);
6969
font-size: var(--font-size-label-small);
7070
font-family: monospace;
71-
padding: 6px 0;
71+
padding: 12px 0;
72+
text-align: center;
7273
}

examples/demo/src/components/LogView.tsx

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { FC } from 'react';
2-
import { useEffect, useMemo, useRef, useState } from 'react';
2+
import { useEffect, useState } from 'react';
33
import {
44
MdDelete,
55
MdKeyboardArrowDown,
@@ -14,20 +14,17 @@ const manager = LogManager.getInstance();
1414
const LogView: FC = () => {
1515
const [entries, setEntries] = useState<LogEntry[]>([]);
1616
const [collapsed, setCollapsed] = useState(false);
17-
const scrollRef = useRef<HTMLDivElement | null>(null);
1817

1918
useEffect(() => {
20-
return manager.subscribe(setEntries);
19+
return manager.subscribe((entry) => {
20+
if (entry) {
21+
setEntries((prev) => [entry, ...prev]);
22+
} else {
23+
setEntries([]);
24+
}
25+
});
2126
}, []);
2227

23-
useEffect(() => {
24-
if (scrollRef.current) {
25-
scrollRef.current.scrollTop = 0;
26-
}
27-
}, [entries]);
28-
29-
const countText = useMemo(() => `(${entries.length})`, [entries.length]);
30-
3128
return (
3229
<section className="logview-panel" data-testid="log_view_container">
3330
<div
@@ -37,20 +34,22 @@ const LogView: FC = () => {
3734
>
3835
<strong>LOGS</strong>
3936
<span className="logview-count" data-testid="log_view_count">
40-
{countText}
37+
({entries.length})
4138
</span>
42-
<button
43-
className="icon-btn"
44-
onClick={(e) => {
45-
e.stopPropagation();
46-
manager.clear();
47-
}}
48-
type="button"
49-
aria-label="Clear logs"
50-
data-testid="log_view_clear_button"
51-
>
52-
<MdDelete />
53-
</button>
39+
{entries.length > 0 && (
40+
<button
41+
className="icon-btn"
42+
onClick={(e) => {
43+
e.stopPropagation();
44+
manager.clear();
45+
}}
46+
type="button"
47+
aria-label="Clear logs"
48+
data-testid="log_view_clear_button"
49+
>
50+
<MdDelete />
51+
</button>
52+
)}
5453
<span
5554
className="icon-btn"
5655
aria-label={collapsed ? 'Expand logs' : 'Collapse logs'}
@@ -59,11 +58,7 @@ const LogView: FC = () => {
5958
</span>
6059
</div>
6160
{!collapsed ? (
62-
<div
63-
className="logview-body"
64-
ref={scrollRef}
65-
data-testid="log_view_list"
66-
>
61+
<div className="logview-body" data-testid="log_view_list">
6762
{entries.length ? (
6863
entries.map((entry, index) => (
6964
<div
@@ -87,7 +82,7 @@ const LogView: FC = () => {
8782
className="log-text"
8883
data-testid={`log_entry_${index}_message`}
8984
>
90-
{entry.message}
85+
{entry.tag}: {entry.message}
9186
</span>
9287
</div>
9388
))

examples/demo/src/pages/Home.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
--os-divider: #e8eaed;
1111
--os-warning-background: #fff8e1;
1212
--os-overlay-scrim: rgba(0, 0, 0, 0.26);
13+
--os-log-background: #1a1b1e;
14+
--os-log-debug: #82aaff;
15+
--os-log-info: #c3e88d;
16+
--os-log-warn: #ffcb6b;
17+
--os-log-error: #ff5370;
18+
--os-log-timestamp: #676e7b;
1319

1420
/* Spacing */
1521
--space-card-gap: 8px;

examples/demo/src/services/LogManager.ts

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ export type LogLevel = 'D' | 'I' | 'W' | 'E';
33
export interface LogEntry {
44
timestamp: string;
55
level: LogLevel;
6+
tag: string;
67
message: string;
78
}
89

9-
type LogListener = (entries: LogEntry[]) => void;
10+
type LogListener = (entry: LogEntry | null) => void;
1011

1112
export default class LogManager {
1213
private static instance: LogManager | null = null;
@@ -21,54 +22,54 @@ export default class LogManager {
2122
return LogManager.instance;
2223
}
2324

25+
getEntries(): LogEntry[] {
26+
return this.entries;
27+
}
28+
2429
subscribe(listener: LogListener): () => void {
2530
this.listeners.add(listener);
26-
listener(this.entries);
2731
return () => {
2832
this.listeners.delete(listener);
2933
};
3034
}
3135

3236
clear(): void {
3337
this.entries = [];
34-
this.emit();
38+
this.emit(null);
3539
}
3640

3741
d(tag: string, message: string): void {
38-
this.append('D', `[${tag}] ${message}`);
42+
this.append('D', tag, message);
3943
console.log(`[D][${tag}] ${message}`);
4044
}
4145

4246
i(tag: string, message: string): void {
43-
this.append('I', `[${tag}] ${message}`);
47+
this.append('I', tag, message);
4448
console.log(`[I][${tag}] ${message}`);
4549
}
4650

4751
w(tag: string, message: string): void {
48-
this.append('W', `[${tag}] ${message}`);
52+
this.append('W', tag, message);
4953
console.warn(`[W][${tag}] ${message}`);
5054
}
5155

5256
e(tag: string, message: string): void {
53-
this.append('E', `[${tag}] ${message}`);
57+
this.append('E', tag, message);
5458
console.error(`[E][${tag}] ${message}`);
5559
}
5660

57-
private append(level: LogLevel, message: string): void {
58-
const timestamp = new Date().toLocaleTimeString('en-US', {
59-
hour: '2-digit',
60-
minute: '2-digit',
61-
second: '2-digit',
62-
hour12: false,
63-
});
64-
this.entries = [{ timestamp, level, message }, ...this.entries].slice(
65-
0,
66-
100,
67-
);
68-
this.emit();
61+
private append(level: LogLevel, tag: string, message: string): void {
62+
const now = new Date();
63+
const timestamp = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
64+
const entry: LogEntry = { timestamp, level, tag, message };
65+
this.entries.unshift(entry);
66+
if (this.entries.length > 100) {
67+
this.entries.length = 100;
68+
}
69+
this.emit(entry);
6970
}
7071

71-
private emit(): void {
72-
this.listeners.forEach((listener) => listener(this.entries));
72+
private emit(entry: LogEntry | null): void {
73+
this.listeners.forEach((listener) => listener(entry));
7374
}
7475
}

0 commit comments

Comments
 (0)