trmnl_preview 0.5.1 → 0.5.3

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.
@@ -0,0 +1,782 @@
1
+ (function () {
2
+ // Define the HTML template as a string.
3
+ // We wrap the SVG in a container <div id="container"> to allow forwarding
4
+ // of the host element's "class" and "style" attributes.
5
+
6
+ let mainContentId = `main-content-${Math.random().toString(36).substring(2)}`;
7
+ let containerId = `container-${Math.random().toString(36).substring(2)}`;
8
+ let contentWrapperId = `container-wrapper-${Math.random()
9
+ .toString(36)
10
+ .substring(2)}`;
11
+ let trmnlComponentIframeId = `trmnl-component-iframe-${Math.random()
12
+ .toString(36)
13
+ .substring(2)}`;
14
+
15
+ const colors = {
16
+ white: {
17
+ start: "#F7F6F6",
18
+ end: "#E9E9E9",
19
+ logo: "#E9E9E9",
20
+ },
21
+ black: {
22
+ start: "#414141",
23
+ end: "#313131",
24
+ logo: "#595959",
25
+ },
26
+ mint: {
27
+ start: "#D9DED0",
28
+ end: "#CFD3C8",
29
+ logo: "#D8DCD1",
30
+ },
31
+ gray: {
32
+ start: "#696e74",
33
+ end: "#696e74",
34
+ logo: "#595959",
35
+ },
36
+ wood: {
37
+ start: "#f9e3cb",
38
+ end: "#ecd4bc",
39
+ logo: "#fdefd5",
40
+ },
41
+ };
42
+
43
+ const contentWrapperTemplate = `<!doctype html>
44
+ <html lang="en">
45
+ <head>
46
+ <link rel="stylesheet" href="https://usetrmnl.com/css/latest/plugins.css"/>
47
+ <script type="text/javascript" src="https://usetrmnl.com/js/latest/plugins.js"></script>
48
+ <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
49
+ <meta charset="utf-8" />
50
+ <title>TRMNL</title>
51
+ </head>
52
+ <body class="trmnl" style="background-color: white !important;">
53
+ <div id="${mainContentId}">CONTENT_PLACEHOLDER</div>
54
+ </body>
55
+ </html>`;
56
+
57
+ const templateHTML = `
58
+ <style>
59
+ :host {
60
+ display: inline-block;
61
+ width: auto;
62
+ }
63
+ #${containerId} {
64
+ width: 100%;
65
+ height: auto;
66
+ }
67
+ svg {
68
+ width: 100%;
69
+ height: auto;
70
+ display: block;
71
+ }
72
+ #${mainContentId} {
73
+ width: 100%;
74
+ height: auto;
75
+ display: block;
76
+ background-opacity: 0;
77
+ }
78
+ #${trmnlComponentIframeId} {
79
+ border: none !important;
80
+ width: 800px;
81
+ height: 480px;
82
+ }
83
+ #${trmnlComponentIframeId}.dark-mode {
84
+ filter: invert(1) brightness(0.9) sepia(25%) contrast(0.75);
85
+ opacity:90%;
86
+ }
87
+ </style>
88
+ <div id="${containerId}">
89
+ <svg width="950px" height="639px" viewBox="0 0 950 639" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
90
+ <title>TRMNL</title>
91
+ <defs>
92
+ <linearGradient x1="50%" y1="0.295017483%" x2="50%" y2="98.7079327%" id="linearGradient-1">
93
+ <stop id="start" stop-color="#F7F6F6" offset="0%"></stop>
94
+ <stop id="end" stop-color="#E9E9E9" offset="100%"></stop>
95
+ </linearGradient>
96
+ <path d="M28.2027372,0 L826.111263,1.81366828e-15 C835.917969,-1.0537935e-15 839.474118,1.02108172 843.059303,2.93845974 C846.644488,4.85583776 849.458162,7.66951208 851.37554,11.2546973 C853.292918,14.8398824 854.314,18.3960311 854.314,28.2027372 L854.314,546.429263 C854.314,556.235969 853.292918,559.792118 851.37554,563.377303 C849.458162,566.962488 846.644488,569.776162 843.059303,571.69354 C839.474118,573.610918 835.917969,574.632 826.111263,574.632 L28.2027372,574.632 C18.3960311,574.632 14.8398824,573.610918 11.2546973,571.69354 C7.66951208,569.776162 4.85583776,566.962488 2.93845974,563.377303 C1.02108172,559.792118 1.79144895e-14,556.235969 -3.08323607e-14,546.429263 L0,28.2027372 C0,18.3960311 1.02108172,14.8398824 2.93845974,11.2546973 C4.85583776,7.66951208 7.66951208,4.85583776 11.2546973,2.93845974 C14.8398824,1.02108172 18.3960311,0 28.2027372,0 Z" id="path-2"></path>
97
+ <filter x="-1.3%" y="-1.7%" width="102.7%" height="104.0%" filterUnits="objectBoundingBox" id="filter-3">
98
+ <feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
99
+ <feGaussianBlur stdDeviation="3.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
100
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.342083698 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
101
+ </filter>
102
+ <path d="M38.5374834,27 L815.462517,27 C819.474351,27 820.929139,27.4177153 822.395806,28.2020972 C823.862472,28.9864791 825.013521,30.1375277 825.797903,31.6041943 C826.582285,33.070861 827,34.5256491 827,38.5374834 L827,495.462517 C827,499.474351 826.582285,500.929139 825.797903,502.395806 C825.013521,503.862472 823.862472,505.013521 822.395806,505.797903 C820.929139,506.582285 819.474351,507 815.462517,507 L38.5374834,507 C34.5256491,507 33.070861,506.582285 31.6041943,505.797903 C30.1375277,505.013521 28.9864791,503.862472 28.2020972,502.395806 C27.4177153,500.929139 27,499.474351 27,495.462517 L27,38.5374834 C27,34.5256491 27.4177153,33.070861 28.2020972,31.6041943 C28.9864791,30.1375277 30.1375277,28.9864791 31.6041943,28.2020972 C33.070861,27.4177153 34.5256491,27 38.5374834,27 Z" id="path-4"></path>
103
+ <filter x="-0.5%" y="-0.8%" width="101.0%" height="101.7%" filterUnits="objectBoundingBox" id="filter-5">
104
+ <feGaussianBlur stdDeviation="3" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
105
+ <feOffset dx="0" dy="2" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
106
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
107
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
108
+ </filter>
109
+ <polygon id="path-6" points="30.4432432 6.94287907 30.4432432 4.15135135 46.3567568 4.15135135 46.3567568 6.94287907 39.9198299 6.94287907 39.9198299 18.6810811 36.8990438 18.6810811 36.8990438 6.94287907"></polygon>
110
+ <filter x="-9.4%" y="-10.3%" width="118.9%" height="120.6%" filterUnits="objectBoundingBox" id="filter-7">
111
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
112
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
113
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
114
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
115
+ </filter>
116
+ <path d="M49.8162162,4.15135135 L49.8162162,18.6810811 L52.8523226,18.6810811 L52.8523226,13.5912453 L61.0721342,13.5912453 C61.6443807,13.5912453 62.0184369,13.7189233 62.2506098,13.9435637 C62.4783178,14.1639612 62.6184648,14.5256765 62.6184648,15.1152338 L62.6184648,18.6810811 L65.6357196,18.6810811 L65.6357196,14.7403994 C65.6357196,13.8468096 65.3447594,13.1148672 64.814929,12.600511 C64.5115665,12.3061097 64.1385024,12.0909964 63.7133483,11.9555874 C64.2208543,11.696457 64.6412955,11.3548891 64.9652461,10.932914 C65.4762248,10.2674527 65.7297297,9.42496011 65.7297297,8.44713669 C65.7297297,7.06980219 65.2916771,5.97468682 64.3582728,5.23449284 C63.4382632,4.50512742 62.0749919,4.15135135 60.2825977,4.15135135 L49.8162162,4.15135135 Z M59.75624,10.8786151 L52.8523226,10.8786151 L52.8523226,6.84422472 L59.75624,6.84422472 C60.760834,6.84422472 61.4784366,6.9832779 61.9403018,7.28832549 C62.3756259,7.57590683 62.6184648,8.03546952 62.6184648,8.8022403 C62.6184648,9.5814535 62.3733935,10.0741526 61.9328604,10.3878162 C61.4714913,10.7164471 60.7551289,10.8786151 59.75624,10.8786151 Z" id="path-8"></path>
117
+ <filter x="-9.4%" y="-10.3%" width="118.9%" height="120.6%" filterUnits="objectBoundingBox" id="filter-9">
118
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
119
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
120
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
121
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
122
+ </filter>
123
+ <polygon id="path-10" points="68.4972973 18.6810811 68.4972973 4.15135135 72.9082435 4.15135135 79.241009 15.0102802 85.554257 4.15135135 89.9459459 4.15135135 89.9459459 18.6810811 86.7802138 18.6810811 86.7802138 7.96393861 80.6210236 18.6810811 77.8417371 18.6810811 71.6825469 7.96393861 71.6825469 18.6810811"></polygon>
124
+ <filter x="-7.0%" y="-10.3%" width="114.0%" height="120.6%" filterUnits="objectBoundingBox" id="filter-11">
125
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
126
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
127
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
128
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
129
+ </filter>
130
+ <polygon id="path-12" points="97.435008 4.15135135 93.4054054 4.15135135 93.4054054 18.6810811 96.4068254 18.6810811 96.4068254 7.50994637 105.999845 18.6810811 110.010811 18.6810811 110.010811 4.15135135 107.028027 4.15135135 107.028027 15.3224861"></polygon>
131
+ <filter x="-9.0%" y="-10.3%" width="118.1%" height="120.6%" filterUnits="objectBoundingBox" id="filter-13">
132
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
133
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
134
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
135
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
136
+ </filter>
137
+ <polygon id="path-14" points="117.380019 4.15135135 114.162162 4.15135135 114.162162 18.6810811 128 18.6810811 128 15.8895534 117.380019 15.8895534"></polygon>
138
+ <filter x="-10.8%" y="-10.3%" width="121.7%" height="120.6%" filterUnits="objectBoundingBox" id="filter-15">
139
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
140
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
141
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
142
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
143
+ </filter>
144
+ <polygon id="path-16" points="6.1435832 0.691891892 13.1459459 3.37533695 11.845606 6.91891892 4.84324324 4.2354993"></polygon>
145
+ <filter x="-18.1%" y="-24.1%" width="136.1%" height="148.2%" filterUnits="objectBoundingBox" id="filter-17">
146
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
147
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
148
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
149
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
150
+ </filter>
151
+ <polygon id="path-18" points="17.5964512 0 20.0648649 7.15103824 16.3062515 8.3027027 13.8378378 1.15166697"></polygon>
152
+ <filter x="-24.1%" y="-18.1%" width="148.2%" height="136.1%" filterUnits="objectBoundingBox" id="filter-19">
153
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
154
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
155
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
156
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
157
+ </filter>
158
+ <polygon id="path-20" points="25.6 8.27152584 21.2525567 14.5297297 17.9891892 12.4852309 22.3366325 6.22702703"></polygon>
159
+ <filter x="-19.7%" y="-18.1%" width="139.4%" height="136.1%" filterUnits="objectBoundingBox" id="filter-21">
160
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
161
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
162
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
163
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
164
+ </filter>
165
+ <polygon id="path-22" points="22.8324324 20.0099988 15.5472692 20.7567568 15.2216216 16.6602715 22.5067605 15.9135135"></polygon>
166
+ <filter x="-19.7%" y="-31.0%" width="139.4%" height="161.9%" filterUnits="objectBoundingBox" id="filter-23">
167
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
168
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
169
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
170
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
171
+ </filter>
172
+ <polygon id="path-24" points="14.009405 24.9081081 8.99459459 19.2742777 11.590595 16.6054054 16.6054054 22.2392877"></polygon>
173
+ <filter x="-19.7%" y="-18.1%" width="139.4%" height="136.1%" filterUnits="objectBoundingBox" id="filter-25">
174
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
175
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
176
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
177
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
178
+ </filter>
179
+ <polygon id="path-26" points="2.76756757 20.9711149 3.9545589 13.8378378 8.3027027 14.3153716 7.11571137 21.4486486"></polygon>
180
+ <filter x="-27.1%" y="-19.7%" width="154.2%" height="139.4%" filterUnits="objectBoundingBox" id="filter-27">
181
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
182
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
183
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
184
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
185
+ </filter>
186
+ <polygon id="path-28" points="0 10.0113136 6.40614303 6.22702703 8.3027027 9.36165939 1.89655719 13.1459459"></polygon>
187
+ <filter x="-18.1%" y="-21.7%" width="136.1%" height="143.4%" filterUnits="objectBoundingBox" id="filter-29">
188
+ <feGaussianBlur stdDeviation="1" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
189
+ <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
190
+ <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
191
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
192
+ </filter>
193
+ </defs>
194
+ <g id="Artboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" >
195
+ <g id="Group" transform="translate(48, 32)">
196
+ <g id="Rectangle">
197
+ <use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
198
+ <use fill="url(#linearGradient-1)" fill-rule="evenodd" xlink:href="#path-2"></use>
199
+ </g>
200
+ <g id="Rectangle">
201
+ <use fill="#E4E2E1" fill-rule="evenodd" xlink:href="#path-4"></use>
202
+ <use fill="black" fill-opacity="1" filter="url(#filter-5)" xlink:href="#path-4"></use>
203
+ </g>
204
+
205
+
206
+
207
+ <foreignobject class="node" x="36" y="34" width="840" height="520"
208
+ style="transform:scale(0.98); position: relative; border-radius: 12px; opacity: 0.9; mix-blend-mode: darken;">
209
+ <div id="${contentWrapperId}"
210
+ style="position: static; width: 100%; height: 100%; max-width: 100%; max-height: 100%;">
211
+ <iframe id="${trmnlComponentIframeId}" src="about:blank"
212
+ style="display:block; position: static; top: 0; left: 0; width: 100%; height: 100%; border: none;"></iframe>
213
+ </div>
214
+ </foreignobject>
215
+
216
+ <g id="logo--brand@vector" transform="translate(363, 529)">
217
+ <g id="Path">
218
+ <use
219
+ class="logo__path"
220
+ fill="#E9E9E9"
221
+ fill-rule="evenodd"
222
+ xlink:href="#path-6"
223
+ ></use>
224
+ <use
225
+ fill="black"
226
+ fill-opacity="1"
227
+ filter="url(#filter-7)"
228
+ xlink:href="#path-6"
229
+ ></use>
230
+ </g>
231
+ <g id="Shape">
232
+ <use
233
+ class="logo__path"
234
+ fill="#E9E9E9"
235
+ fill-rule="evenodd"
236
+ xlink:href="#path-8"
237
+ ></use>
238
+ <use
239
+ fill="black"
240
+ fill-opacity="1"
241
+ filter="url(#filter-9)"
242
+ xlink:href="#path-8"
243
+ ></use>
244
+ </g>
245
+ <g id="Path">
246
+ <use
247
+ class="logo__path"
248
+ fill="#E9E9E9"
249
+ fill-rule="evenodd"
250
+ xlink:href="#path-10"
251
+ ></use>
252
+ <use
253
+ fill="black"
254
+ fill-opacity="1"
255
+ filter="url(#filter-11)"
256
+ xlink:href="#path-10"
257
+ ></use>
258
+ </g>
259
+ <g id="Path">
260
+ <use
261
+ class="logo__path"
262
+ fill="#E9E9E9"
263
+ fill-rule="evenodd"
264
+ xlink:href="#path-12"
265
+ ></use>
266
+ <use
267
+ fill="black"
268
+ fill-opacity="1"
269
+ filter="url(#filter-13)"
270
+ xlink:href="#path-12"
271
+ ></use>
272
+ </g>
273
+ <g id="Path">
274
+ <use
275
+ class="logo__path"
276
+ fill="#E9E9E9"
277
+ fill-rule="evenodd"
278
+ xlink:href="#path-14"
279
+ ></use>
280
+ <use
281
+ fill="black"
282
+ fill-opacity="1"
283
+ filter="url(#filter-15)"
284
+ xlink:href="#path-14"
285
+ ></use>
286
+ </g>
287
+ <g id="Path">
288
+ <use
289
+ class="logo__path"
290
+ fill="#E9E9E9"
291
+ fill-rule="evenodd"
292
+ xlink:href="#path-16"
293
+ ></use>
294
+ <use
295
+ fill="black"
296
+ fill-opacity="1"
297
+ filter="url(#filter-17)"
298
+ xlink:href="#path-16"
299
+ ></use>
300
+ </g>
301
+ <g id="Path">
302
+ <use
303
+ class="logo__path"
304
+ fill="#E9E9E9"
305
+ fill-rule="evenodd"
306
+ xlink:href="#path-18"
307
+ ></use>
308
+ <use
309
+ fill="black"
310
+ fill-opacity="1"
311
+ filter="url(#filter-19)"
312
+ xlink:href="#path-18"
313
+ ></use>
314
+ </g>
315
+ <g id="Path">
316
+ <use
317
+ class="logo__path"
318
+ fill="#E9E9E9"
319
+ fill-rule="evenodd"
320
+ xlink:href="#path-20"
321
+ ></use>
322
+ <use
323
+ fill="black"
324
+ fill-opacity="1"
325
+ filter="url(#filter-21)"
326
+ xlink:href="#path-20"
327
+ ></use>
328
+ </g>
329
+ <g id="Path">
330
+ <use
331
+ class="logo__path"
332
+ fill="#E9E9E9"
333
+ fill-rule="evenodd"
334
+ xlink:href="#path-22"
335
+ ></use>
336
+ <use
337
+ fill="black"
338
+ fill-opacity="1"
339
+ filter="url(#filter-23)"
340
+ xlink:href="#path-22"
341
+ ></use>
342
+ </g>
343
+ <g id="Path">
344
+ <use
345
+ class="logo__path"
346
+ fill="#E9E9E9"
347
+ fill-rule="evenodd"
348
+ xlink:href="#path-24"
349
+ ></use>
350
+ <use
351
+ fill="black"
352
+ fill-opacity="1"
353
+ filter="url(#filter-25)"
354
+ xlink:href="#path-24"
355
+ ></use>
356
+ </g>
357
+ <g id="Path">
358
+ <use
359
+ class="logo__path"
360
+ fill="#E9E9E9"
361
+ fill-rule="evenodd"
362
+ xlink:href="#path-26"
363
+ ></use>
364
+ <use
365
+ fill="black"
366
+ fill-opacity="1"
367
+ filter="url(#filter-27)"
368
+ xlink:href="#path-26"
369
+ ></use>
370
+ </g>
371
+ <g id="Path">
372
+ <use
373
+ class="logo__path"
374
+ fill="#E9E9E9"
375
+ fill-rule="evenodd"
376
+ xlink:href="#path-28"
377
+ ></use>
378
+ <use
379
+ fill="black"
380
+ fill-opacity="1"
381
+ filter="url(#filter-29)"
382
+ xlink:href="#path-28"
383
+ ></use>
384
+ </g>
385
+ </g>
386
+ </g>
387
+ </g>
388
+ </svg>
389
+ </div>
390
+ `;
391
+
392
+ class TRMNL extends HTMLElement {
393
+ constructor() {
394
+ super();
395
+ console.log("TRMNL element constructed.");
396
+ this._src = null; // Store the src attribute value
397
+ this._color = "white"; // Default color
398
+ this._contentMode = "external"; // Default to external src mode
399
+ this._htmlContent = ""; // Store HTML content
400
+ this._darkMode = null; // Store dark mode setting
401
+
402
+ // Attach a shadow root and append the template content
403
+ const shadow = this.attachShadow({ mode: "open" });
404
+ const template = document.createElement("template");
405
+ template.innerHTML = templateHTML;
406
+ shadow.appendChild(template.content.cloneNode(true));
407
+
408
+ // Get reference to the iframe for later use
409
+ this._iframe = this.shadowRoot.querySelector(
410
+ `#${trmnlComponentIframeId}`
411
+ );
412
+
413
+ // Setup iframe load handler once
414
+ if (this._iframe) {
415
+ this._iframe.onload = () => {
416
+ this._handleIframeLoaded();
417
+ };
418
+ }
419
+
420
+ // Process any slotted content
421
+ this._processSlottedContent();
422
+
423
+ // Initialize dark mode media query listener if needed
424
+ this._darkModeMediaQuery = window.matchMedia(
425
+ "(prefers-color-scheme: dark)"
426
+ );
427
+ this._darkModeMediaQuery.addEventListener("change", () => {
428
+ this._updateDarkMode();
429
+ });
430
+ }
431
+
432
+ _handleIframeLoaded() {
433
+ if (this._contentMode === "internal" && this._htmlContent) {
434
+ try {
435
+ const currentSrc = this._iframe.getAttribute("src");
436
+ if (currentSrc === "about:blank") {
437
+ const iframeDoc = this._iframe.contentWindow.document;
438
+
439
+ // Step 1: Write the base shell with placeholder container
440
+ iframeDoc.open();
441
+ iframeDoc.write(
442
+ contentWrapperTemplate.replace(
443
+ `<div id="${mainContentId}">CONTENT_PLACEHOLDER</div>`,
444
+ `<div id="${mainContentId}"></div>`
445
+ )
446
+ );
447
+ iframeDoc.close();
448
+
449
+ // Step 2: Wait for the contentWrapperTemplate to parse & render
450
+ this._iframe.contentWindow.addEventListener(
451
+ "DOMContentLoaded",
452
+ () => {
453
+ const container = iframeDoc.getElementById(mainContentId);
454
+ if (!container) {
455
+ console.warn(
456
+ `${mainContentId} container not found inside iframe`
457
+ );
458
+ return;
459
+ }
460
+
461
+ // Step 3: Apply the transition & inject content
462
+ // Check if not Safari and if startViewTransition is available
463
+ const isSafari = /^((?!chrome|android).)*safari/i.test(
464
+ navigator.userAgent
465
+ );
466
+ if (
467
+ !isSafari &&
468
+ typeof iframeDoc.startViewTransition === "function"
469
+ ) {
470
+ iframeDoc.startViewTransition(() => {
471
+ container.innerHTML = this._htmlContent;
472
+ });
473
+ } else {
474
+ container.innerHTML = this._htmlContent;
475
+ }
476
+
477
+ console.log(
478
+ "Dynamic content injected" +
479
+ (!isSafari ? " with View Transition" : "")
480
+ );
481
+ },
482
+ { once: true }
483
+ );
484
+
485
+ const isSafari = /^((?!chrome|android).)*safari/i.test(
486
+ navigator.userAgent
487
+ );
488
+ if (isSafari) {
489
+ console.log("Safari browser detected");
490
+ }
491
+ // Safari needs additional help to render content correctly
492
+ if (isSafari) {
493
+ const container = iframeDoc.getElementById(mainContentId);
494
+
495
+ setTimeout(() => {
496
+ if (container && this._htmlContent) {
497
+ container.innerHTML = this._htmlContent;
498
+ console.log(
499
+ "Applied additional Safari-specific content update"
500
+ );
501
+ }
502
+ }, 100);
503
+ }
504
+ }
505
+ } catch (e) {
506
+ console.error("Error injecting HTML with transition into iframe:", e);
507
+ }
508
+ }
509
+ }
510
+
511
+ static get observedAttributes() {
512
+ return ["src", "class", "style", "color", "dark"];
513
+ }
514
+
515
+ attributeChangedCallback(name, oldValue, newValue) {
516
+ if (name === "src") {
517
+ console.log(
518
+ `attributeChangedCallback: 'src' changed from ${oldValue} to ${newValue}`
519
+ );
520
+ this._src = newValue;
521
+ this._contentMode = "external";
522
+ this.updateIframe();
523
+ } else if (name === "class" || name === "style") {
524
+ this.updateContainerAttribute(name, newValue);
525
+ } else if (name === "color") {
526
+ this._color = newValue || "white"; // Default to white if not specified
527
+ this.updateColors();
528
+ } else if (name === "dark") {
529
+ this._darkMode = newValue;
530
+ this._updateDarkMode();
531
+ }
532
+ }
533
+
534
+ connectedCallback() {
535
+ console.log("TRMNL connectedCallback invoked.");
536
+
537
+ // Process any existing content from innerHTML
538
+ this._processSlottedContent();
539
+
540
+ if (this.hasAttribute("src")) {
541
+ const src = this.getAttribute("src");
542
+ console.log("connectedCallback found src attribute:", src);
543
+ this._src = src;
544
+ this._contentMode = "external";
545
+ this.updateIframe();
546
+ }
547
+
548
+ // Initialize container attributes for class and style
549
+ this.updateContainerAttribute("class", this.getAttribute("class"));
550
+ this.updateContainerAttribute("style", this.getAttribute("style"));
551
+
552
+ // Initialize color
553
+ if (this.hasAttribute("color")) {
554
+ this._color = this.getAttribute("color");
555
+ }
556
+ this.updateColors();
557
+
558
+ // Initialize dark mode
559
+ if (this.hasAttribute("dark")) {
560
+ this._darkMode = this.getAttribute("dark");
561
+ this._updateDarkMode();
562
+ }
563
+
564
+ // Set up the mutation observer to handle content changes
565
+ this._setupMutationObserver();
566
+ }
567
+
568
+ disconnectedCallback() {
569
+ // Clean up the mutation observer when element is removed
570
+ if (this._observer) {
571
+ this._observer.disconnect();
572
+ }
573
+
574
+ // Remove media query listener
575
+ if (this._darkModeMediaQuery) {
576
+ this._darkModeMediaQuery.removeEventListener("change", () => {
577
+ this._updateDarkMode();
578
+ });
579
+ }
580
+ }
581
+
582
+ _updateDarkMode() {
583
+ if (!this._iframe) return;
584
+
585
+ // Step 1: Remove the class
586
+ this._iframe.classList.remove("dark-mode");
587
+
588
+ // Step 2: Force reflow by reading offsetHeight
589
+ // This ensures the class removal is flushed
590
+ void this._iframe.offsetHeight;
591
+
592
+ // Step 3: Re-apply the class based on logic
593
+ const shouldEnableDark =
594
+ this._darkMode === "true" ||
595
+ (this._darkMode === "auto" && this._darkModeMediaQuery.matches);
596
+
597
+ if (shouldEnableDark) {
598
+ this._iframe.classList.add("dark-mode");
599
+ }
600
+ }
601
+
602
+ _setupMutationObserver() {
603
+ // Create a MutationObserver to detect content changes
604
+ this._observer = new MutationObserver((mutations) => {
605
+ mutations.forEach((mutation) => {
606
+ if (mutation.type === "childList") {
607
+ this._processSlottedContent();
608
+ }
609
+ });
610
+ });
611
+
612
+ // Observe changes to the element's child nodes
613
+ this._observer.observe(this, { childList: true });
614
+ }
615
+
616
+ _processSlottedContent() {
617
+ // Check if there's content inside the tags
618
+ if (this.innerHTML.trim()) {
619
+ // Set content mode to internal and store HTML
620
+ this._contentMode = "internal";
621
+ this._htmlContent = this.innerHTML;
622
+ this._prepareThenInjectHTML();
623
+ }
624
+ }
625
+
626
+ _prepareThenInjectHTML() {
627
+ if (!this._iframe) {
628
+ console.error("Iframe not found in shadow DOM");
629
+ return;
630
+ }
631
+
632
+ // Set iframe to about:blank to ensure same-origin
633
+ // This will trigger the onload handler which will inject the content
634
+ this._iframe.setAttribute("src", "about:blank");
635
+ }
636
+
637
+ updateIframe() {
638
+ // Delay updating the iframe until the next animation frame
639
+ requestAnimationFrame(() => {
640
+ if (this._iframe) {
641
+ if (this._contentMode === "external" && this._src) {
642
+ this._iframe.setAttribute("src", this._src);
643
+ console.log(`iframe src set to: ${this._src}`);
644
+ } else if (this._contentMode === "internal") {
645
+ // For internal content, ensure we're at about:blank
646
+ this._prepareThenInjectHTML();
647
+ }
648
+ } else {
649
+ console.error(
650
+ "iframe element not found in shadow DOM during updateIframe."
651
+ );
652
+ }
653
+ });
654
+ }
655
+
656
+ updateContainerAttribute(name, value) {
657
+ const container = this.shadowRoot.querySelector("#container");
658
+ if (container) {
659
+ if (value !== null) {
660
+ container.setAttribute(name, value);
661
+ } else {
662
+ container.removeAttribute(name);
663
+ }
664
+ }
665
+ }
666
+
667
+ updateColors() {
668
+ // Validate that the color exists in our colors object
669
+ if (!colors[this._color]) {
670
+ console.warn(`Color "${this._color}" not found, defaulting to white`);
671
+ this._color = "white";
672
+ }
673
+
674
+ const colorSet = colors[this._color];
675
+
676
+ // Update the gradient stops
677
+ const startStop = this.shadowRoot.querySelector("#start");
678
+ const endStop = this.shadowRoot.querySelector("#end");
679
+
680
+ if (startStop && endStop) {
681
+ startStop.setAttribute("stop-color", colorSet.start);
682
+ endStop.setAttribute("stop-color", colorSet.end);
683
+ console.log(`Updated gradient colors to ${this._color} theme`);
684
+ }
685
+
686
+ // Update all SVG elements in the logo that use the fill color
687
+ const logoGroup = this.shadowRoot.querySelector("#logo--brand\\@vector");
688
+ if (logoGroup) {
689
+ // Find all 'use' elements with fill="#E9E9E9" and update them
690
+ const logoElements = logoGroup.querySelectorAll(".logo__path");
691
+ logoElements.forEach((element) => {
692
+ element.setAttribute("fill", colorSet.logo);
693
+ });
694
+ }
695
+ }
696
+
697
+ // JavaScript API methods
698
+
699
+ /**
700
+ * Set the color theme: 'white', 'black', or 'mint'
701
+ * @param {string} color - The color theme to use
702
+ */
703
+ setColor(color) {
704
+ this._color = color;
705
+ this.updateColors();
706
+ return this; // For chaining
707
+ }
708
+
709
+ /**
710
+ * Set dark mode: 'true', 'false', or 'auto'
711
+ * @param {string} mode - The dark mode setting
712
+ */
713
+ setDark(mode) {
714
+ this._darkMode = mode;
715
+ this._updateDarkMode();
716
+ return this; // For chaining
717
+ }
718
+
719
+ /**
720
+ * Set HTML content directly, wrapping it in the template
721
+ * @param {string} html - HTML content to display
722
+ */
723
+ setHTML(html) {
724
+ this._contentMode = "internal";
725
+ this._htmlContent = html;
726
+ this._prepareThenInjectHTML();
727
+ return this; // For chaining
728
+ }
729
+
730
+ /**
731
+ * Clear all content
732
+ */
733
+ clearContent() {
734
+ if (this._iframe) {
735
+ this._htmlContent = "";
736
+
737
+ if (this._contentMode === "internal") {
738
+ // Reset to about:blank to clear content
739
+ this._iframe.setAttribute("src", "about:blank");
740
+ } else {
741
+ // For external mode, set src to empty
742
+ this._src = "";
743
+ this._iframe.setAttribute("src", "about:blank");
744
+ }
745
+ }
746
+ return this; // For chaining
747
+ }
748
+
749
+ /**
750
+ * Set iframe source to an external URL
751
+ * @param {string} src - URL to load in the iframe
752
+ */
753
+ setSrc(src) {
754
+ this._contentMode = "external";
755
+ this._src = src;
756
+ this.updateIframe();
757
+ return this; // For chaining
758
+ }
759
+
760
+ /**
761
+ * Get current HTML content (for internal content mode only)
762
+ * @returns {string} The current HTML content or empty string if in external mode
763
+ */
764
+ getHTML() {
765
+ // Simply return the stored HTML content
766
+ return this._contentMode === "internal" ? this._htmlContent : "";
767
+ }
768
+
769
+ /**
770
+ * Set dark mode: 'true', 'false', or 'auto'
771
+ * @param {string} mode - The dark mode setting
772
+ */
773
+ setDarkMode(mode) {
774
+ this._darkMode = mode;
775
+ this._updateDarkMode();
776
+ return this; // For chaining
777
+ }
778
+ }
779
+
780
+ // Register the custom element using a hyphenated tag name
781
+ customElements.define("trmnl-frame", TRMNL);
782
+ })();