tecitheme 0.3.2 → 0.3.4

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.
Files changed (156) hide show
  1. package/.eslintrc.cjs +24 -0
  2. package/.frontmatter/content/mediaDb.json +1 -0
  3. package/.frontmatter/templates/article.md +11 -0
  4. package/.gitpod.yml +19 -0
  5. package/.vscode/ltex.dictionary.en-US.txt +3 -0
  6. package/.vscode/settings.json +7 -0
  7. package/dist/assets/js/store.d.ts +2 -0
  8. package/dist/assets/js/store.js +4 -0
  9. package/{components → dist/components}/CountrySelector.svelte +2 -2
  10. package/{components → dist/components}/Footer.svelte +24 -60
  11. package/{components → dist/components}/Footer.svelte.d.ts +2 -5
  12. package/{components → dist/components}/NewsGrid.svelte +3 -3
  13. package/{components → dist/components}/Video.svelte +1 -1
  14. package/{get-content.d.ts → dist/get-content.d.ts} +2 -1
  15. package/{get-content.js → dist/get-content.js} +5 -2
  16. package/{layouts → dist/layouts}/blocks.svelte +19 -27
  17. package/{layouts → dist/layouts}/blocks.svelte.d.ts +4 -4
  18. package/{site_config.json → dist/site_config.json} +1 -1
  19. package/frontmatter.json +17 -0
  20. package/mdsvex.config.js +19 -0
  21. package/netlify.toml +7 -0
  22. package/package.json +22 -46
  23. package/postcss.config.cjs +13 -0
  24. package/src/app.css +49 -0
  25. package/src/app.html +22 -0
  26. package/src/global.d.ts +5 -0
  27. package/src/lib/assets/TECi_logo.svelte +177 -0
  28. package/src/lib/assets/js/store.js +4 -0
  29. package/src/lib/components/Banner.svelte +91 -0
  30. package/src/lib/components/Button.svelte +12 -0
  31. package/src/lib/components/CTA.svelte +36 -0
  32. package/src/lib/components/CTABranded.svelte +15 -0
  33. package/src/lib/components/CTASplitImage.svelte +27 -0
  34. package/src/lib/components/Card.svelte +93 -0
  35. package/src/lib/components/ContentTwoColumns.svelte +47 -0
  36. package/src/lib/components/CountrySelector.svelte +167 -0
  37. package/src/lib/components/FeatureGrid.svelte +40 -0
  38. package/src/lib/components/Figure.svelte +37 -0
  39. package/src/lib/components/Footer.svelte +270 -0
  40. package/src/lib/components/Header.svelte +1230 -0
  41. package/src/lib/components/HeadingCentered.svelte +33 -0
  42. package/src/lib/components/Hero.svelte +72 -0
  43. package/src/lib/components/Icon.svelte +138 -0
  44. package/src/lib/components/LogoCloud.svelte +25 -0
  45. package/src/lib/components/Math.svelte +24 -0
  46. package/src/lib/components/MediaFeature.svelte +66 -0
  47. package/src/lib/components/Modal.svelte +68 -0
  48. package/src/lib/components/NewsGrid.svelte +182 -0
  49. package/src/lib/components/PricingTable.svelte +92 -0
  50. package/src/lib/components/SidebarContent.svelte +122 -0
  51. package/src/lib/components/Stats.svelte +34 -0
  52. package/src/lib/components/Subscribe.svelte +24 -0
  53. package/src/lib/components/Testimonial.svelte +169 -0
  54. package/src/lib/components/ThreeColumn.svelte +19 -0
  55. package/src/lib/components/TrialForm.svelte +302 -0
  56. package/src/lib/components/Video.svelte +118 -0
  57. package/src/lib/components/Wrap.svelte +12 -0
  58. package/src/lib/get-content.js +98 -0
  59. package/src/lib/layouts/blocks.svelte +93 -0
  60. package/src/lib/req_utils.js +63 -0
  61. package/src/lib/site_config.json +11 -0
  62. package/src/lib/utils.js +92 -0
  63. package/src/lib/variables.ts +3 -0
  64. package/src/routes/+layout.server.js +20 -0
  65. package/src/routes/+layout.svelte +24 -0
  66. package/src/routes/+page.md +61 -0
  67. package/src/routes/features/+page.md +78 -0
  68. package/src/routes/news/+page.md +21 -0
  69. package/src/routes/news/[slug]/+page.svelte +33 -0
  70. package/src/routes/news/[slug]/+page.ts +16 -0
  71. package/src/routes/news/filter/[tag]/+page.svelte +36 -0
  72. package/src/routes/news/filter/[tag]/+page.ts +14 -0
  73. package/src/routes/news/post1.md +45 -0
  74. package/src/routes/news/post2.md +46 -0
  75. package/src/routes/pathfinder/+page.md +240 -0
  76. package/src/routes/pathfinder/news/+page.md +20 -0
  77. package/src/routes/posts.json/+server.js +9 -0
  78. package/src/routes/product/+page.md +240 -0
  79. package/src/routes/product/news/+page.md +20 -0
  80. package/src/routes/product/trial/+page.svelte +7 -0
  81. package/src/routes/sidebar/+page.md +357 -0
  82. package/static/favicon.ico +0 -0
  83. package/static/uploads/company_pathfinder.png +0 -0
  84. package/static/uploads/company_petrasim.png +0 -0
  85. package/static/uploads/company_pyrosim.jpg +0 -0
  86. package/static/uploads/fire.jpg +0 -0
  87. package/static/uploads/pyrosim_libraries_386x395.png +0 -0
  88. package/static/uploads/rocks.jpg +0 -0
  89. package/static/uploads/water.jpg +0 -0
  90. package/svelte.config.js +32 -0
  91. package/tailwind.config.cjs +26 -0
  92. package/tsconfig.json +32 -0
  93. package/vite.config.js +20 -0
  94. package/components/MetaSocial.svelte +0 -15
  95. package/components/MetaSocial.svelte.d.ts +0 -29
  96. /package/{assets → dist/assets}/TECi_logo.svelte +0 -0
  97. /package/{assets → dist/assets}/TECi_logo.svelte.d.ts +0 -0
  98. /package/{components → dist/components}/Banner.svelte +0 -0
  99. /package/{components → dist/components}/Banner.svelte.d.ts +0 -0
  100. /package/{components → dist/components}/Button.svelte +0 -0
  101. /package/{components → dist/components}/Button.svelte.d.ts +0 -0
  102. /package/{components → dist/components}/CTA.svelte +0 -0
  103. /package/{components → dist/components}/CTA.svelte.d.ts +0 -0
  104. /package/{components → dist/components}/CTABranded.svelte +0 -0
  105. /package/{components → dist/components}/CTABranded.svelte.d.ts +0 -0
  106. /package/{components → dist/components}/CTASplitImage.svelte +0 -0
  107. /package/{components → dist/components}/CTASplitImage.svelte.d.ts +0 -0
  108. /package/{components → dist/components}/Card.svelte +0 -0
  109. /package/{components → dist/components}/Card.svelte.d.ts +0 -0
  110. /package/{components → dist/components}/ContentTwoColumns.svelte +0 -0
  111. /package/{components → dist/components}/ContentTwoColumns.svelte.d.ts +0 -0
  112. /package/{components → dist/components}/CountrySelector.svelte.d.ts +0 -0
  113. /package/{components → dist/components}/FeatureGrid.svelte +0 -0
  114. /package/{components → dist/components}/FeatureGrid.svelte.d.ts +0 -0
  115. /package/{components → dist/components}/Figure.svelte +0 -0
  116. /package/{components → dist/components}/Figure.svelte.d.ts +0 -0
  117. /package/{components → dist/components}/Header.svelte +0 -0
  118. /package/{components → dist/components}/Header.svelte.d.ts +0 -0
  119. /package/{components → dist/components}/HeadingCentered.svelte +0 -0
  120. /package/{components → dist/components}/HeadingCentered.svelte.d.ts +0 -0
  121. /package/{components → dist/components}/Hero.svelte +0 -0
  122. /package/{components → dist/components}/Hero.svelte.d.ts +0 -0
  123. /package/{components → dist/components}/Icon.svelte +0 -0
  124. /package/{components → dist/components}/Icon.svelte.d.ts +0 -0
  125. /package/{components → dist/components}/LogoCloud.svelte +0 -0
  126. /package/{components → dist/components}/LogoCloud.svelte.d.ts +0 -0
  127. /package/{components → dist/components}/Math.svelte +0 -0
  128. /package/{components → dist/components}/Math.svelte.d.ts +0 -0
  129. /package/{components → dist/components}/MediaFeature.svelte +0 -0
  130. /package/{components → dist/components}/MediaFeature.svelte.d.ts +0 -0
  131. /package/{components → dist/components}/Modal.svelte +0 -0
  132. /package/{components → dist/components}/Modal.svelte.d.ts +0 -0
  133. /package/{components → dist/components}/NewsGrid.svelte.d.ts +0 -0
  134. /package/{components → dist/components}/PricingTable.svelte +0 -0
  135. /package/{components → dist/components}/PricingTable.svelte.d.ts +0 -0
  136. /package/{components → dist/components}/SidebarContent.svelte +0 -0
  137. /package/{components → dist/components}/SidebarContent.svelte.d.ts +0 -0
  138. /package/{components → dist/components}/Stats.svelte +0 -0
  139. /package/{components → dist/components}/Stats.svelte.d.ts +0 -0
  140. /package/{components → dist/components}/Subscribe.svelte +0 -0
  141. /package/{components → dist/components}/Subscribe.svelte.d.ts +0 -0
  142. /package/{components → dist/components}/Testimonial.svelte +0 -0
  143. /package/{components → dist/components}/Testimonial.svelte.d.ts +0 -0
  144. /package/{components → dist/components}/ThreeColumn.svelte +0 -0
  145. /package/{components → dist/components}/ThreeColumn.svelte.d.ts +0 -0
  146. /package/{components → dist/components}/TrialForm.svelte +0 -0
  147. /package/{components → dist/components}/TrialForm.svelte.d.ts +0 -0
  148. /package/{components → dist/components}/Video.svelte.d.ts +0 -0
  149. /package/{components → dist/components}/Wrap.svelte +0 -0
  150. /package/{components → dist/components}/Wrap.svelte.d.ts +0 -0
  151. /package/{req_utils.d.ts → dist/req_utils.d.ts} +0 -0
  152. /package/{req_utils.js → dist/req_utils.js} +0 -0
  153. /package/{utils.d.ts → dist/utils.d.ts} +0 -0
  154. /package/{utils.js → dist/utils.js} +0 -0
  155. /package/{variables.d.ts → dist/variables.d.ts} +0 -0
  156. /package/{variables.js → dist/variables.js} +0 -0
@@ -0,0 +1,302 @@
1
+ <script lang="ts">
2
+ import CountrySelector from "$lib/components/CountrySelector.svelte";
3
+ import Icon from "$lib/components/Icon.svelte";
4
+ import { onMount } from "svelte";
5
+ import { scrollTo, validateEmail } from "$lib/utils.js";
6
+ import { variables } from "$lib/variables";
7
+
8
+ onMount(() => {
9
+ setTimeout(() => {
10
+ timePassed = true;
11
+ }, 3000);
12
+ });
13
+
14
+ let resellerModal = false;
15
+ let country = "sel";
16
+ let name = "";
17
+ let email = "";
18
+ let product = 0;
19
+ let valid = false;
20
+ let message = "";
21
+ let error = "";
22
+ let answer = "";
23
+ let submitted = false;
24
+ let waiting = false;
25
+ let timePassed = false;
26
+
27
+ $: if (
28
+ country != "sel" &&
29
+ name != "" &&
30
+ validateEmail(email) &&
31
+ product != 0 &&
32
+ answer == "" &&
33
+ timePassed
34
+ ) {
35
+ valid = true;
36
+ } else {
37
+ valid = false;
38
+ }
39
+
40
+ $: if (submitted == true && message == "") {
41
+ waiting = true;
42
+ scrollTo("trial-request");
43
+ } else {
44
+ waiting = false;
45
+ }
46
+
47
+ const submitForm = async () => {
48
+ submitted = true;
49
+ error = "";
50
+
51
+ try {
52
+ const submit = await fetch(variables.trialEndpoint, {
53
+ method: "POST",
54
+ body: JSON.stringify({
55
+ name,
56
+ email,
57
+ country,
58
+ product,
59
+ }),
60
+ });
61
+ message = await submit.json();
62
+ } catch (err) {
63
+ console.log(err);
64
+ }
65
+ };
66
+ </script>
67
+
68
+ <div class="mt-10 sm:mt-0">
69
+ <div class="mt-8 md:grid md:grid-cols-3 md:gap-6">
70
+ <div class="md:col-span-1">
71
+ <div class="prose px-4 sm:px-0">
72
+ <h2>30-day Trial Request</h2>
73
+ <p>
74
+ Please complete the form and click "Send Request". <b
75
+ >All fields are required.</b
76
+ >
77
+ </p>
78
+ <p>
79
+ Within a few minutes, you will receive an email message containing a
80
+ download link.
81
+ </p>
82
+ <p>
83
+ If you need assistance, please send an email to <a
84
+ href="mailto:sales@thunderheadeng.com">sales</a
85
+ >.
86
+ </p>
87
+ </div>
88
+ </div>
89
+ <div class="mt-5 md:col-span-2 md:mt-0">
90
+ <form id="trial-request" on:submit|preventDefault={submitForm}>
91
+ <div class="overflow-hidden border shadow">
92
+ {#if message}
93
+ <div class="prose bg-white px-4 py-5 sm:p-6">
94
+ <p>
95
+ Thank you <strong>{message.name}</strong> for requesting a trial
96
+ of {#if message.product == 1}PyroSim{:else if message.product == 2}Pathfinder{:else if message.product == 3}PyroSim
97
+ and Pathfinder{/if}!<br />
98
+ You will receive an email to <strong>{message.email}</strong>
99
+ with your activation key{#if message.product == 3}s{/if}
100
+ in a few moments.
101
+ </p>
102
+ {#if message.product == 1}
103
+ <h3>PyroSim</h3>
104
+ <p>
105
+ To download the most recent version visit the <a
106
+ href="https://support.thunderheadeng.com/pyrosim/"
107
+ >PyroSim Support</a
108
+ > page.
109
+ </p>
110
+ {:else if message.product == 2}
111
+ <h3>Pathfinder</h3>
112
+ <p>
113
+ To download the most recent version visit the <a
114
+ href="https://support.thunderheadeng.com/pathfinder/"
115
+ >Pathfinder Support</a
116
+ > page.
117
+ </p>
118
+ {:else if message.product == 3}
119
+ <h3>PyroSim</h3>
120
+ <p>
121
+ To download the most recent version visit the <a
122
+ href="https://support.thunderheadeng.com/pyrosim/"
123
+ >PyroSim Support</a
124
+ > page.
125
+ </p>
126
+ <h3>Pathfinder</h3>
127
+ <p>
128
+ To download the most recent version visit the <a
129
+ href="https://support.thunderheadeng.com/pathfinder/"
130
+ >Pathfinder Support</a
131
+ > page.
132
+ </p>
133
+ {/if}
134
+ <h3>Need Help?</h3>
135
+ <p>
136
+ Please email <a href="mailto:support@thunderheadeng.com"
137
+ >support@thunderheadeng.com</a
138
+ > if you have any questions.
139
+ </p>
140
+ </div>
141
+ {:else if error}
142
+ <p>There was an error: {error}</p>
143
+ {:else if waiting}
144
+ <div id="waiting" class="mx-auto p-12">
145
+ <p class="pb-8 text-center font-bold">
146
+ Waiting for Trial Approval...
147
+ </p>
148
+ <Icon classes="h-24 w-24 mx-auto animate-pulse" />
149
+ </div>
150
+ {:else}
151
+ <div class="space-y-6 bg-white px-4 py-5 sm:p-6">
152
+ <fieldset>
153
+ <div>
154
+ <legend class="text-lg font-bold text-gray-900">
155
+ Personal Information
156
+ </legend>
157
+ </div>
158
+ <div class="flex flex-row items-center pt-4 align-middle">
159
+ <label
160
+ for="name"
161
+ class="block whitespace-nowrap pr-2 font-medium text-gray-700"
162
+ >
163
+ Full Name:
164
+ </label>
165
+ <input
166
+ id="name"
167
+ type="text"
168
+ name="name"
169
+ bind:value={name}
170
+ class="w-full border-0 border-b-2 border-gray-500 p-1"
171
+ />
172
+ </div>
173
+ <div class="flex flex-row items-center pt-4 align-middle">
174
+ <label
175
+ for="email"
176
+ class="block pr-2 font-medium text-gray-700"
177
+ >
178
+ Email:
179
+ </label>
180
+ <input
181
+ id="email"
182
+ type="text"
183
+ name="email"
184
+ bind:value={email}
185
+ class="w-full border-0 border-b-2 border-gray-500 p-1"
186
+ />
187
+ </div>
188
+ <div class="flex flex-row items-center pt-4 align-middle">
189
+ <label
190
+ for="country"
191
+ class="block pr-2 font-medium text-gray-700"
192
+ >
193
+ Country:
194
+ </label>
195
+ <input
196
+ id="country"
197
+ type="hidden"
198
+ name="country"
199
+ value={country}
200
+ />
201
+ <CountrySelector
202
+ bind:selection={country}
203
+ bind:resellerModal
204
+ />
205
+ </div>
206
+ </fieldset>
207
+ <fieldset>
208
+ <div>
209
+ <legend class="text-lg font-bold text-gray-900">
210
+ What would you like to try?
211
+ </legend>
212
+ </div>
213
+ <div class="mt-4 space-y-4">
214
+ <div class="flex items-center">
215
+ <input
216
+ id="pyrosim"
217
+ name="product"
218
+ type="radio"
219
+ value={1}
220
+ bind:group={product}
221
+ class="h-4 w-4 border-gray-300 text-blue-600 focus:ring-teci-blue-dark"
222
+ />
223
+ <label
224
+ for="pyrosim"
225
+ class="ml-3 block text-sm font-medium text-gray-700"
226
+ >
227
+ PyroSim
228
+ </label>
229
+ </div>
230
+ <div class="flex items-center">
231
+ <input
232
+ id="pathfinder"
233
+ name="product"
234
+ type="radio"
235
+ value={2}
236
+ bind:group={product}
237
+ class="h-4 w-4 border-gray-300 text-blue-600 focus:ring-teci-blue-dark"
238
+ />
239
+ <label
240
+ for="pathfinder"
241
+ class="ml-3 block text-sm font-medium text-gray-700"
242
+ >
243
+ Pathfinder
244
+ </label>
245
+ </div>
246
+ <div class="flex items-center">
247
+ <input
248
+ id="pyropath"
249
+ name="product"
250
+ type="radio"
251
+ value={3}
252
+ bind:group={product}
253
+ class="h-4 w-4 border-gray-300 text-blue-600 focus:ring-teci-blue-dark"
254
+ />
255
+ <label
256
+ for="pyropath"
257
+ class="ml-3 block text-sm font-medium text-gray-700"
258
+ >
259
+ PyroSim and Pathfinder
260
+ </label>
261
+ </div>
262
+ </div>
263
+ </fieldset>
264
+ <input
265
+ class="confident"
266
+ id="answer"
267
+ type="text"
268
+ name="answer"
269
+ bind:value={answer}
270
+ placeholder="Correct answers only..."
271
+ />
272
+ </div>
273
+ <div class="px-4 py-3 text-right sm:px-6">
274
+ <button
275
+ type="submit"
276
+ disabled={!valid}
277
+ class="inline-flex justify-center border border-transparent py-2 px-4 text-sm font-medium text-white shadow-sm {valid ===
278
+ true
279
+ ? 'bg-teci-blue-light hover:bg-teci-blue-dark focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2'
280
+ : 'cursor-not-allowed bg-gray-300'}"
281
+ >
282
+ Send Request
283
+ </button>
284
+ {#if answer}
285
+ <p>
286
+ Something is wrong with the form, please email
287
+ support@thunderheadeng.com.
288
+ </p>
289
+ {/if}
290
+ </div>
291
+ {/if}
292
+ </div>
293
+ </form>
294
+ </div>
295
+ </div>
296
+ </div>
297
+
298
+ <style lang="postcss">
299
+ .confident {
300
+ @apply hidden;
301
+ }
302
+ </style>
@@ -0,0 +1,118 @@
1
+ <script>
2
+ import { onMount } from 'svelte'
3
+
4
+ export let data={};
5
+ export let v="";
6
+ export let thumbnail="";
7
+
8
+ let id="";
9
+ let thumb="";
10
+ let youtube=false;
11
+ let videoURL="";
12
+
13
+ onMount(() => {
14
+ var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));
15
+
16
+ if ("IntersectionObserver" in window) {
17
+ var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
18
+ entries.forEach(function(video) {
19
+ if (video.isIntersecting) {
20
+ for (var source in video.target.children) {
21
+ var videoSource = video.target.children[source];
22
+ if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
23
+ videoSource.src = videoSource.dataset.src;
24
+ }
25
+ }
26
+
27
+ video.target.load();
28
+ video.target.classList.remove("lazy");
29
+ lazyVideoObserver.unobserve(video.target);
30
+ }
31
+ });
32
+ });
33
+
34
+ lazyVideos.forEach(function(lazyVideo) {
35
+ lazyVideoObserver.observe(lazyVideo);
36
+ });
37
+ }
38
+ })
39
+
40
+ if (v) {
41
+ if (v.includes("mp4")) {
42
+ youtube = false;
43
+ videoURL = `https://teci-files.imgix.net/www/videos/${v}`;
44
+ } else {
45
+ youtube = true;
46
+ id = v;
47
+ };
48
+ } else if (data.v) {
49
+ if (data.v.includes("mp4")) {
50
+ youtube = false;
51
+ videoURL = `https://teci-files.imgix.net/www/videos/${data.v}`;
52
+ } else {
53
+ youtube = true;
54
+ id = data.v;
55
+ };
56
+ } else {
57
+ id = "";
58
+ videoURL = "";
59
+ };
60
+
61
+ if (thumbnail) {
62
+ thumb = `https://teci-files.imgix.net/www/images/${thumbnail}?w=1214&fit=clip&auto=compress&auto=format`;
63
+ } else if (data.thumbnail) {
64
+ thumb = `https://teci-files.imgix.net/www/images/${data.thumbnail}?w=1214&fit=clip&auto=compress&auto=format`;
65
+ } else if (id) {
66
+ if (youtube) {
67
+ thumb = `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`;
68
+ }
69
+ }
70
+ </script>
71
+
72
+ <section class="aspect-video not-prose w-full border border-gray-200 bg-black shadow-md">
73
+ {#if youtube}
74
+ <iframe
75
+ title="YouTube Video ID {id}"
76
+ class="aspect-video w-full"
77
+ frameborder="0"
78
+ allow="autoplay; encrypted-media"
79
+ allowfullscreen
80
+ src="https://www.youtube.com/embed/${id}?autoplay=1&start=0&mute=1"
81
+ srcdoc="{`
82
+ <style>
83
+ body, .youtubeembed {
84
+ width: 100%;
85
+ height: 100%;
86
+ margin: 0;
87
+ position: absolute;
88
+ display: flex;
89
+ justify-content: center;
90
+ object-fit: cover;
91
+ }
92
+ </style>
93
+ <a
94
+ href='https://www.youtube.com/embed/${id}?autoplay=1&start=0&mute=1'
95
+ class='youtubeembed'
96
+ >
97
+ <img
98
+ src='${thumb}'
99
+ class='youtubeembed'
100
+ />
101
+ <svg
102
+ version='1.1'
103
+ viewBox='0 0 68 48'
104
+ width='68px'
105
+ style='position: relative;'
106
+ >
107
+ <path d='M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z' fill='#f00'></path>
108
+ <path d='M 45,24 27,14 27,34' fill='#fff'></path>
109
+ </svg>
110
+ </a>
111
+ `}"
112
+ />
113
+ {:else}
114
+ <video class="lazy aspect-video w-full" autoplay muted loop playsinline controls poster={thumb}>
115
+ <source data-src={videoURL} type="video/mp4">
116
+ </video>
117
+ {/if}
118
+ </section>
@@ -0,0 +1,12 @@
1
+ <script>
2
+ export let tag = "div";
3
+ export let when = true;
4
+ </script>
5
+
6
+ {#if when}
7
+ <svelte:element this={tag} {...$$restProps}>
8
+ <slot />
9
+ </svelte:element>
10
+ {:else}
11
+ <slot />
12
+ {/if}
@@ -0,0 +1,98 @@
1
+ // get-content.js
2
+ // HTML parser from https://github.com/html-to-text/node-html-to-text
3
+ import { convert } from "html-to-text";
4
+ import { dev } from "$app/environment";
5
+
6
+ const getContent = async (content='') => {
7
+
8
+ let indexData = [];
9
+ let iterableContentFiles = Object.entries([]);
10
+ let sortedIndex = [];
11
+
12
+ // Use 'content' variable to determine files to import.
13
+ switch (content) {
14
+ case "news":
15
+ iterableContentFiles = Object.entries(
16
+ import.meta.glob("/src/routes/news/*(!(+page)).md")
17
+ );
18
+ break;
19
+ default:
20
+ iterableContentFiles = Object.entries(
21
+ import.meta.glob("/src/routes/**/*(!(+page)).md")
22
+ );
23
+ }
24
+
25
+ const allContent = await Promise.all(
26
+ iterableContentFiles.map(async ([path, resolver]) => {
27
+ const contentPath = path.slice(11, -3);
28
+ const file = await resolver();
29
+ const metadata = file.metadata;
30
+ const today = new Date();
31
+
32
+ if (
33
+ metadata.notIndexed ||
34
+ (dev ? false : metadata.draft) ||
35
+ (dev ? false : new Date(metadata.date) > today)
36
+ ) {
37
+ return;
38
+ } else {
39
+ var html = file.default.render().html;
40
+ var plaintext = convert(html, {
41
+ baseElements: {
42
+ orderBy: "occurrence",
43
+ },
44
+ wordwrap: false,
45
+ selectors: [
46
+ { selector: "h1", format: "skip" },
47
+ { selector: "h2", options: { uppercase: false } },
48
+ { selector: "a", options: { ignoreHref: true } },
49
+ { selector: "a.button", format: "skip" },
50
+ { selector: "a.btn", format: "skip" },
51
+ { selector: "aside", format: "skip" },
52
+ { selector: "ul", options: { itemPrefix: "- " } },
53
+ { selector: "img", format: "skip" },
54
+ ],
55
+ })
56
+ .replace(/\n\n\n/gm, " ")
57
+ .replace(/\n\n/g, " ")
58
+ .replace(/\n/g, " ")
59
+ .replace(/\"/g, "'")
60
+ .trim();
61
+
62
+ if (metadata && contentPath && plaintext) {
63
+ return {
64
+ meta: metadata,
65
+ path: contentPath,
66
+ text: plaintext,
67
+ };
68
+ }
69
+ }
70
+ })
71
+ );
72
+
73
+ for (let i = 0; i < allContent.length; i++) {
74
+ if (allContent[i]) {
75
+ let today = new Date();
76
+ let postdate = allContent[i].meta.date
77
+ ? new Date(allContent[i].meta.date)
78
+ : today;
79
+ let entry = {
80
+ title: allContent[i].meta.title,
81
+ content: allContent[i].text,
82
+ summary: allContent[i].meta.summary,
83
+ date: postdate,
84
+ slug: allContent[i].path,
85
+ categories: allContent[i].meta.categories,
86
+ };
87
+ indexData.push(entry);
88
+ } else {
89
+ continue;
90
+ }
91
+ }
92
+
93
+ sortedIndex = indexData.slice().sort((a, b) => new Date(b.date) - new Date(a.date));
94
+
95
+ return sortedIndex;
96
+ }
97
+
98
+ export default getContent
@@ -0,0 +1,93 @@
1
+ <script>
2
+ import CTA from "$lib/components/CTA.svelte";
3
+ import HeadingCentered from "$lib/components/HeadingCentered.svelte";
4
+ import MediaFeature from "$lib/components/MediaFeature.svelte";
5
+ import Modal from "$lib/components/Modal.svelte";
6
+ import NewsGrid from "$lib/components/NewsGrid.svelte";
7
+ import SidebarContent from "$lib/components/SidebarContent.svelte";
8
+ import ThreeColumn from "$lib/components/ThreeColumn.svelte";
9
+ import TrialForm from "$lib/components/TrialForm.svelte";
10
+ import Video from "$lib/components/Video.svelte";
11
+ import Hero from "$lib/components/Hero.svelte";
12
+ import CTABranded from "$lib/components/CTABranded.svelte";
13
+ import FeatureGrid from "$lib/components/FeatureGrid.svelte";
14
+ import LogoCloud from "$lib/components/LogoCloud.svelte";
15
+ import CtaSplitImage from "$lib/components/CTASplitImage.svelte";
16
+ import ContentTwoColumns from "$lib/components/ContentTwoColumns.svelte";
17
+ import PricingTable from "$lib/components/PricingTable.svelte";
18
+ import Stats from "$lib/components/Stats.svelte";
19
+ import Testimonial from "$lib/components/Testimonial.svelte";
20
+
21
+ let blocks = [
22
+ { ref: "cta-center", component: CTA },
23
+ { ref: "heading-centered", component: HeadingCentered },
24
+ { ref: "media-feature", component: MediaFeature },
25
+ { ref: "modal", component: Modal },
26
+ { ref: "news-grid", component: NewsGrid },
27
+ { ref: "sidebar-content", component: SidebarContent },
28
+ { ref: "three-column", component: ThreeColumn },
29
+ { ref: "trial-form", component: TrialForm },
30
+ { ref: "video", component: Video },
31
+ { ref: "hero", component: Hero },
32
+ { ref: "cta-branded", component: CTABranded },
33
+ { ref: "feature-grid", component: FeatureGrid },
34
+ { ref: "logo-cloud", component: LogoCloud },
35
+ { ref: "cta-split-image", component: CtaSplitImage },
36
+ { ref: "content-two-columns", component: ContentTwoColumns },
37
+ { ref: "pricing-table", component: PricingTable },
38
+ { ref: "stats", component: Stats },
39
+ { ref: "testimonial", component: Testimonial },
40
+ ];
41
+
42
+ export let title;
43
+ export let date;
44
+ export let summary;
45
+ export let image;
46
+ export let lastmod;
47
+ export let layout;
48
+ export let page_sections;
49
+
50
+ let featuredImage;
51
+
52
+ if (image) {
53
+ featuredImage = "https://teci-files.imgix.net/www/images/" + image + "?w=1200&h=627&fit=crop&auto=compress&auto=format";
54
+ } else {
55
+ featuredImage = "https://teci-files.imgix.net/www/images/teci_icon_250.png";
56
+ }
57
+ </script>
58
+
59
+ <svelte:head>
60
+ <title>{title} | Thunderhead Engineering</title>
61
+ <meta data-key="description" name="description" content={summary}>
62
+ <meta property="og:type" content="article" />
63
+ <meta property="og:title" content={title} />
64
+ <meta name="twitter:title" content={title} />
65
+ <meta property="og:description" content={summary} />
66
+ <meta name="twitter:description" content={summary} />
67
+ <meta name="twitter:card" content="summary_large_image" />
68
+ <meta name="twitter:site" content="@thunderheadeng" />
69
+ <meta name="twitter:creator" content="@thunderheadeng" />
70
+ <meta property="og:image" content={featuredImage} />
71
+ <meta name="twitter:card" content={featuredImage} />
72
+ <!-- <meta property="og:image:width" content={coverWidth} />
73
+ <meta property="og:image:height" content={coverHeight} /> -->
74
+ </svelte:head>
75
+
76
+ <article class="flex flex-col space-y-16 {layout}">
77
+ {#each page_sections as section}
78
+ {#if section && section.fieldGroup === "sidebar-content"}
79
+ <svelte:component
80
+ this={blocks.find((obj) => obj.ref === section.fieldGroup).component}
81
+ data={section}
82
+ {title}
83
+ {date}
84
+ {lastmod}><slot /></svelte:component
85
+ >
86
+ {:else if section && section.fieldGroup != "sidebar-content"}
87
+ <svelte:component
88
+ this={blocks.find((obj) => obj.ref === section.fieldGroup).component}
89
+ data={section}
90
+ />
91
+ {/if}
92
+ {/each}
93
+ </article>
@@ -0,0 +1,63 @@
1
+ import { browser } from "$app/environment";
2
+
3
+ export function browserGet(key) {
4
+ if (browser) {
5
+ const item = localStorage.getItem(key);
6
+ if (item) {
7
+ return JSON.parse(item);
8
+ }
9
+ }
10
+ return null;
11
+ }
12
+
13
+ export function browserSet(key, value) {
14
+ if (browser) {
15
+ localStorage.setItem(key, value);
16
+ }
17
+ return null;
18
+ }
19
+
20
+ export async function post(fetch, url, body) {
21
+ let customError = false;
22
+ try {
23
+ let headers = {};
24
+ if (!(body instanceof FormData)) {
25
+ headers["Content-Type"] = "application/json";
26
+ body = JSON.stringify(body);
27
+ }
28
+ const token = browserGet("token");
29
+ if (token) {
30
+ headers["X-UltraCart-Api-Version"] = "2017-03-01";
31
+ headers[Accept] = "application/json";
32
+ headers["x-ultracart-simple-key"] = token;
33
+ }
34
+ const res = await fetch(url, {
35
+ method: "POST",
36
+ body,
37
+ headers,
38
+ });
39
+ if (!res.ok) {
40
+ try {
41
+ const data = await res.json();
42
+ const error = data.message[0].messages[0];
43
+ customError = true;
44
+ throw { id: error.id, message: error.message };
45
+ } catch (err) {
46
+ console.log(err);
47
+ throw err;
48
+ }
49
+ }
50
+ try {
51
+ const json = await res.json();
52
+ return json;
53
+ } catch (err) {
54
+ console.log(err);
55
+ throw { id: "", message: "An unknown error has occured." };
56
+ }
57
+ } catch (err) {
58
+ console.log(err);
59
+ throw customError
60
+ ? err
61
+ : { id: "", message: "An unknown error has occured" };
62
+ }
63
+ }