@pablozaiden/webapp 0.1.0 → 0.2.1

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.
@@ -1,4 +1,5 @@
1
1
  import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { appWebSocketUrl } from "../api-client";
2
3
 
3
4
  export type RealtimeStatus = "connecting" | "open" | "closed";
4
5
  export type RealtimeAction = "created" | "updated" | "changed" | "deleted";
@@ -71,8 +72,7 @@ export function useRealtime<TEvent>({
71
72
  for (const [key, value] of Object.entries(filters ?? {})) {
72
73
  if (value) params.set(key, value);
73
74
  }
74
- const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
75
- socket = new WebSocket(`${protocol}//${window.location.host}${path}${params.size ? `?${params.toString()}` : ""}`);
75
+ socket = new WebSocket(appWebSocketUrl(`${path}${params.size ? `?${params.toString()}` : ""}`));
76
76
  setStatus("connecting");
77
77
  socket.onopen = () => {
78
78
  retryRef.current = 0;
@@ -0,0 +1,26 @@
1
+ import type { ReactNode } from "react";
2
+ import { createRoot, type Root } from "react-dom/client";
3
+
4
+ declare global {
5
+ var __pablozaidenWebAppRoots: WeakMap<Element, Root> | undefined;
6
+ }
7
+
8
+ function roots(): WeakMap<Element, Root> {
9
+ globalThis.__pablozaidenWebAppRoots ??= new WeakMap<Element, Root>();
10
+ return globalThis.__pablozaidenWebAppRoots;
11
+ }
12
+
13
+ export function renderWebApp(element: ReactNode, container: Element | string = "root"): Root {
14
+ const target = typeof container === "string" ? document.getElementById(container) : container;
15
+ if (!target) {
16
+ throw new Error(`Unable to find React root container: ${container}`);
17
+ }
18
+ const registry = roots();
19
+ let root = registry.get(target);
20
+ if (!root) {
21
+ root = createRoot(target);
22
+ registry.set(target, root);
23
+ }
24
+ root.render(element);
25
+ return root;
26
+ }
@@ -444,6 +444,9 @@ textarea::placeholder {
444
444
  }
445
445
 
446
446
  .wapp-panel {
447
+ min-width: 0;
448
+ max-width: 100%;
449
+ box-sizing: border-box;
447
450
  border: 1px solid var(--wapp-border-soft);
448
451
  border-radius: 1.5rem;
449
452
  background: var(--wapp-surface);
@@ -550,6 +553,10 @@ textarea::placeholder {
550
553
  margin-bottom: 1rem;
551
554
  }
552
555
 
556
+ .wapp-entity-header > div:first-child {
557
+ min-width: 0;
558
+ }
559
+
553
560
  .wapp-entity-header h2 {
554
561
  margin: 0;
555
562
  font-size: 1.125rem;
@@ -580,12 +587,15 @@ textarea::placeholder {
580
587
  }
581
588
 
582
589
  .wapp-data-list {
590
+ max-width: 100%;
591
+ box-sizing: border-box;
583
592
  overflow: hidden;
584
593
  border: 1px solid var(--wapp-border-soft);
585
594
  border-radius: 0.875rem;
586
595
  }
587
596
 
588
597
  .wapp-data-list-row {
598
+ box-sizing: border-box;
589
599
  width: 100%;
590
600
  display: flex;
591
601
  align-items: center;
@@ -697,6 +707,14 @@ textarea::placeholder {
697
707
  background: var(--wapp-surface);
698
708
  }
699
709
 
710
+ .wapp-auth-dialog {
711
+ width: min(28rem, calc(100vw - 2rem));
712
+ }
713
+
714
+ .wapp-auth-dialog .wapp-dialog-body:empty {
715
+ display: none;
716
+ }
717
+
700
718
  .wapp-button {
701
719
  min-height: 2.375rem;
702
720
  border: 1px solid var(--wapp-border);
@@ -1014,6 +1032,17 @@ textarea::placeholder {
1014
1032
  font-size: 0.8125rem;
1015
1033
  }
1016
1034
 
1035
+ .wapp-inline-select {
1036
+ min-height: 2.375rem;
1037
+ border: 1px solid var(--wapp-border);
1038
+ border-radius: 0.375rem;
1039
+ background: var(--wapp-surface);
1040
+ color: var(--wapp-text);
1041
+ box-shadow: var(--wapp-shadow);
1042
+ padding: 0.5rem 2rem 0.5rem 0.75rem;
1043
+ font-size: 0.8125rem;
1044
+ }
1045
+
1017
1046
  .wapp-field textarea {
1018
1047
  min-height: 8rem;
1019
1048
  resize: vertical;
@@ -1035,6 +1064,45 @@ textarea::placeholder {
1035
1064
  color: var(--wapp-muted);
1036
1065
  }
1037
1066
 
1067
+ .wapp-shutdown-countdown {
1068
+ display: grid;
1069
+ gap: 0.5rem;
1070
+ margin-top: 0.75rem;
1071
+ font-weight: 600;
1072
+ }
1073
+
1074
+ .wapp-shutdown-message {
1075
+ color: #dc2626;
1076
+ font-size: 0.875rem;
1077
+ }
1078
+
1079
+ :root.dark .wapp-shutdown-message {
1080
+ color: #f87171;
1081
+ }
1082
+
1083
+ .wapp-shutdown-progress {
1084
+ width: 100%;
1085
+ height: 0.375rem;
1086
+ overflow: hidden;
1087
+ border-radius: 999px;
1088
+ background: #fecaca;
1089
+ }
1090
+
1091
+ :root.dark .wapp-shutdown-progress {
1092
+ background: #7f1d1d;
1093
+ }
1094
+
1095
+ .wapp-shutdown-progress-bar {
1096
+ height: 100%;
1097
+ border-radius: inherit;
1098
+ background: #ef4444;
1099
+ transition: width 1s linear;
1100
+ }
1101
+
1102
+ :root.dark .wapp-shutdown-progress-bar {
1103
+ background: #f87171;
1104
+ }
1105
+
1038
1106
  .wapp-segmented {
1039
1107
  display: flex;
1040
1108
  width: 100%;
@@ -1088,6 +1156,12 @@ textarea::placeholder {
1088
1156
  padding: 0.75rem;
1089
1157
  }
1090
1158
 
1159
+ .wapp-grid-2 {
1160
+ display: grid;
1161
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1162
+ gap: 0.75rem;
1163
+ }
1164
+
1091
1165
  .wapp-list-row + .wapp-list-row {
1092
1166
  border-top: 1px solid var(--wapp-border-soft);
1093
1167
  }
@@ -1180,11 +1254,11 @@ textarea::placeholder {
1180
1254
 
1181
1255
  .wapp-dialog-title {
1182
1256
  display: flex;
1183
- align-items: center;
1257
+ align-items: flex-start;
1184
1258
  justify-content: space-between;
1185
1259
  gap: 1rem;
1186
1260
  border-bottom: 1px solid var(--wapp-border);
1187
- padding: 1rem 1.5rem;
1261
+ padding: 1rem 1.5rem 0.75rem;
1188
1262
  }
1189
1263
 
1190
1264
  .wapp-dialog h2 {
@@ -1192,6 +1266,12 @@ textarea::placeholder {
1192
1266
  font-size: 1.125rem;
1193
1267
  }
1194
1268
 
1269
+ .wapp-dialog-title p {
1270
+ margin: 0.25rem 0 0;
1271
+ color: var(--wapp-muted);
1272
+ line-height: 1.35;
1273
+ }
1274
+
1195
1275
  .wapp-dialog-close {
1196
1276
  display: inline-flex;
1197
1277
  align-items: center;
@@ -1274,6 +1354,28 @@ textarea::placeholder {
1274
1354
 
1275
1355
  .wapp-main-content {
1276
1356
  padding: 1rem;
1357
+ overflow-x: hidden;
1358
+ }
1359
+
1360
+ .wapp-panel-header,
1361
+ .wapp-entity-header {
1362
+ flex-wrap: wrap;
1363
+ }
1364
+
1365
+ .wapp-panel-actions,
1366
+ .wapp-entity-header-actions {
1367
+ width: 100%;
1368
+ justify-content: flex-start;
1369
+ }
1370
+
1371
+ .wapp-data-list-row {
1372
+ gap: 0.5rem;
1373
+ }
1374
+
1375
+ .wapp-data-list-row-meta,
1376
+ .wapp-data-list-row-badge,
1377
+ .wapp-data-list-row-actions {
1378
+ min-width: 0;
1277
1379
  }
1278
1380
 
1279
1381
  .wapp-mobile-only {