Preview.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import { Dynamic } from "solid-js/web";
  2. import { WidgetRenderer } from "./WidgetRenderer";
  3. import { getGrid } from "../grids/registry";
  4. import type { DashboardGridConfig } from "../types/grid";
  5. import { createMemo, createSignal, onMount, Show, For } from "solid-js";
  6. import type { WidgetConfig } from "../types/widget";
  7. export function Preview() {
  8. const [widgets, setWidgets] = createSignal<WidgetConfig[]>([]);
  9. const [gridConfig, setGridConfig] = createSignal<DashboardGridConfig>({
  10. templateId: null,
  11. widgetPlacements: [],
  12. });
  13. const [error, setError] = createSignal<string>("");
  14. // Calculate scale to fit grid inside viewport
  15. const scale = createMemo(() => {
  16. const grid = gridConfig().templateId
  17. ? getGrid(gridConfig().templateId!)
  18. : null;
  19. if (!grid) return 1;
  20. const gridWidth = grid.template?.width || 800;
  21. const gridHeight = grid.template?.height || 600;
  22. const viewportWidth = window.innerWidth - 40; // Add margin for safety
  23. const viewportHeight = window.innerHeight - 40; // Add margin for safety
  24. const scaleX = viewportWidth / gridWidth;
  25. const scaleY = viewportHeight / gridHeight;
  26. // Use slightly smaller scale to ensure nothing clips
  27. return Math.min(scaleX, scaleY) * 0.98; // 98% to add buffer
  28. });
  29. onMount(() => {
  30. try {
  31. const urlParams = new URLSearchParams(window.location.search);
  32. const configParam = urlParams.get("config");
  33. if (configParam) {
  34. const decoded = decodeURIComponent(configParam);
  35. const config = JSON.parse(decoded);
  36. // Support both old format (array) and new format (object with widgets and grid)
  37. if (Array.isArray(config)) {
  38. setWidgets(config);
  39. } else {
  40. if (config.widgets) {
  41. setWidgets(config.widgets);
  42. }
  43. if (config.grid) {
  44. setGridConfig(config.grid);
  45. }
  46. }
  47. } else {
  48. setError("No configuration found in URL");
  49. }
  50. } catch (err) {
  51. console.error("Error loading config:", err);
  52. setError("Failed to load dashboard configuration");
  53. }
  54. });
  55. return (
  56. <div
  57. onClick={() => window.location.reload()}
  58. style={{
  59. width: "100vw",
  60. height: "100vh",
  61. position: "fixed",
  62. top: "0",
  63. left: "0",
  64. background: "var(--bg, #fff)",
  65. overflow: "hidden",
  66. display: "flex",
  67. "align-items": "center",
  68. "justify-content": "center",
  69. padding: "20px",
  70. "box-sizing": "border-box",
  71. }}
  72. >
  73. <Show when={error()}>
  74. <div
  75. style={{
  76. padding: "2rem",
  77. "text-align": "center",
  78. color: "var(--gray)",
  79. }}
  80. >
  81. <h2>Error</h2>
  82. <p>{error()}</p>
  83. </div>
  84. </Show>
  85. <Show when={!error() && widgets().length > 0}>
  86. <div
  87. data-grid-container
  88. style={{
  89. width: gridConfig().templateId
  90. ? `${getGrid(gridConfig().templateId!)?.template.width || 800}px`
  91. : "100%",
  92. height: gridConfig().templateId
  93. ? `${getGrid(gridConfig().templateId!)?.template.height || 600}px`
  94. : "100%",
  95. position: "relative",
  96. transform: `scale(${scale()})`,
  97. "transform-origin": "center center",
  98. "flex-shrink": "0",
  99. }}
  100. >
  101. {/* Render grid template if selected */}
  102. <Show when={gridConfig().templateId}>
  103. {/* @ts-ignore */}
  104. {() => {
  105. const grid = getGrid(gridConfig().templateId!);
  106. return grid ? <Dynamic component={grid.Component} /> : null;
  107. }}
  108. </Show>
  109. {/* Render widgets */}
  110. <For each={widgets()}>
  111. {(widget) => <WidgetRenderer config={widget} locked={true} />}
  112. </For>
  113. </div>
  114. </Show>
  115. <Show when={!error() && widgets().length === 0}>
  116. <div
  117. style={{
  118. padding: "2rem",
  119. "text-align": "center",
  120. color: "var(--gray)",
  121. }}
  122. >
  123. <p>No widgets to display</p>
  124. </div>
  125. </Show>
  126. </div>
  127. );
  128. }