html_compose.gallery.resources

  1class IframeScripts:
  2    parent = """
  3// Iframe auto-sizing: uses adoptedStyleSheets to survive HTML morphs
  4window._iframeSizer ??= (() => {
  5  const SELECTOR = "iframe.o-showcase-content";
  6  const sheet = new CSSStyleSheet();
  7  document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
  8
  9  const sync = () => {
 10    const rules = [];
 11    for (const frame of document.querySelectorAll(SELECTOR)) {
 12      const height = frame.contentDocument?.body?.scrollHeight;
 13      if (height && frame.id) rules.push(`#${CSS.escape(frame.id)} { height: ${height}px; }`);
 14    }
 15    // Only update when we have heights - preserves rules when iframe not yet ready
 16    if (rules.length) sheet.replaceSync(rules.join("\\n"));
 17  };
 18
 19  const resizeObs = new ResizeObserver(sync);
 20
 21  const observe = () => {
 22    for (const frame of document.querySelectorAll(SELECTOR)) {
 23      if (frame.contentDocument?.body) resizeObs.observe(frame.contentDocument.body);
 24      frame.onload = () => {
 25        if (frame.contentDocument?.body) resizeObs.observe(frame.contentDocument.body);
 26        sync();
 27      };
 28    }
 29    sync();
 30  };
 31
 32  // MutationObserver runs indefinitely (never disconnected)
 33  new MutationObserver(observe).observe(document.body, { childList: true, subtree: true, attributes: true });
 34  return { observe };
 35})();
 36window._iframeSizer.observe();"""
 37
 38
 39NAV_STYLES = """
 40:host {
 41  display: block;
 42  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
 43  font-size: 14px;
 44  padding: 12px 0;
 45}
 46ul {
 47  list-style: none;
 48  margin: 0;
 49  padding: 0;
 50}
 51details {
 52  margin: 0;
 53}
 54summary {
 55  cursor: pointer;
 56  padding: 6px 16px;
 57  color: #333;
 58  font-weight: 500;
 59  user-select: none;
 60}
 61summary:hover {
 62  background: #f5f5f5;
 63}
 64details > ul {
 65  padding-left: 12px;
 66}
 67details details summary {
 68  font-weight: 400;
 69  color: #666;
 70  padding: 4px 16px;
 71  font-size: 13px;
 72}
 73a {
 74  display: block;
 75  padding: 4px 16px;
 76  color: #0066cc;
 77  text-decoration: none;
 78  font-size: 13px;
 79}
 80a:hover {
 81  background: #e8f4fc;
 82}
 83"""
 84
 85GALLERY_STYLES = """
 86/* Gallery base styles */
 87* {
 88  box-sizing: border-box;
 89}
 90
 91body {
 92  margin: 0;
 93  padding: 0;
 94  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
 95  background: #f5f5f5;
 96  color: #333;
 97}
 98
 99/* Main layout */
100.o-gallery-container {
101  display: flex;
102  flex-direction: row;
103  align-items: stretch;
104  height: 100vh;
105}
106
107/* Left navigation panel */
108.o-left-panel {
109  flex: 0 0 240px;
110  overflow-y: auto;
111  overflow-x: hidden;
112  background: #fff;
113  border-right: 1px solid #e0e0e0;
114}
115
116/* Hide the empty right panel */
117.o-right-panel {
118  display: none;
119}
120
121/* Center content panel */
122.o-center-panel {
123  flex: 1;
124  display: flex;
125  flex-direction: column;
126  gap: 24px;
127  padding: 24px;
128  overflow-y: auto;
129  background: #f5f5f5;
130}
131
132/* Showcase card container */
133.o-showcase-card {
134  flex-shrink: 0;  /* Don't shrink - overflow and scroll instead */
135  background: #fff;
136  border: 1px solid #e0e0e0;
137  border-radius: 6px;
138  overflow: hidden;
139  box-shadow: 0 1px 3px rgba(0,0,0,0.04);
140}
141
142/* Showcase header */
143.o-showcase-header {
144  display: flex;
145  justify-content: space-between;
146  align-items: center;
147  padding: 10px 16px;
148  font-size: 14px;
149  font-weight: 500;
150  color: #555;
151  background: #fafafa;
152  border-bottom: 1px solid #e0e0e0;
153}
154
155.o-showcase-title {
156  flex: 1;
157}
158
159.o-showcase-link {
160  color: #888;
161  text-decoration: none;
162  padding: 4px 8px;
163  border-radius: 4px;
164  font-size: 13px;
165}
166
167.o-showcase-link:hover {
168  background: #e8e8e8;
169  color: #333;
170}
171
172/* Showcase content container */
173.o-showcase-content {
174  background: #fff;
175}
176
177/* Iframe showcases */
178iframe.o-showcase-content {
179  display: block;
180  border: none;
181  width: 100%;
182  flex-shrink: 0;
183  overflow: hidden;
184}
185"""
class IframeScripts:
 2class IframeScripts:
 3    parent = """
 4// Iframe auto-sizing: uses adoptedStyleSheets to survive HTML morphs
 5window._iframeSizer ??= (() => {
 6  const SELECTOR = "iframe.o-showcase-content";
 7  const sheet = new CSSStyleSheet();
 8  document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
 9
10  const sync = () => {
11    const rules = [];
12    for (const frame of document.querySelectorAll(SELECTOR)) {
13      const height = frame.contentDocument?.body?.scrollHeight;
14      if (height && frame.id) rules.push(`#${CSS.escape(frame.id)} { height: ${height}px; }`);
15    }
16    // Only update when we have heights - preserves rules when iframe not yet ready
17    if (rules.length) sheet.replaceSync(rules.join("\\n"));
18  };
19
20  const resizeObs = new ResizeObserver(sync);
21
22  const observe = () => {
23    for (const frame of document.querySelectorAll(SELECTOR)) {
24      if (frame.contentDocument?.body) resizeObs.observe(frame.contentDocument.body);
25      frame.onload = () => {
26        if (frame.contentDocument?.body) resizeObs.observe(frame.contentDocument.body);
27        sync();
28      };
29    }
30    sync();
31  };
32
33  // MutationObserver runs indefinitely (never disconnected)
34  new MutationObserver(observe).observe(document.body, { childList: true, subtree: true, attributes: true });
35  return { observe };
36})();
37window._iframeSizer.observe();"""
parent = '\n// Iframe auto-sizing: uses adoptedStyleSheets to survive HTML morphs\nwindow._iframeSizer ??= (() => {\n const SELECTOR = "iframe.o-showcase-content";\n const sheet = new CSSStyleSheet();\n document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];\n\n const sync = () => {\n const rules = [];\n for (const frame of document.querySelectorAll(SELECTOR)) {\n const height = frame.contentDocument?.body?.scrollHeight;\n if (height && frame.id) rules.push(`#${CSS.escape(frame.id)} { height: ${height}px; }`);\n }\n // Only update when we have heights - preserves rules when iframe not yet ready\n if (rules.length) sheet.replaceSync(rules.join("\\n"));\n };\n\n const resizeObs = new ResizeObserver(sync);\n\n const observe = () => {\n for (const frame of document.querySelectorAll(SELECTOR)) {\n if (frame.contentDocument?.body) resizeObs.observe(frame.contentDocument.body);\n frame.onload = () => {\n if (frame.contentDocument?.body) resizeObs.observe(frame.contentDocument.body);\n sync();\n };\n }\n sync();\n };\n\n // MutationObserver runs indefinitely (never disconnected)\n new MutationObserver(observe).observe(document.body, { childList: true, subtree: true, attributes: true });\n return { observe };\n})();\nwindow._iframeSizer.observe();'