Skip to content

Commit 9906486

Browse files
committed
feat: implement widget asset fetching script and update feedback modal with success message handling
1 parent 7b8218e commit 9906486

File tree

10 files changed

+123
-18
lines changed

10 files changed

+123
-18
lines changed

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
"scripts": {
77
"astro": "astro",
88
"build": "astro check && astro build",
9-
"dev": "astro dev",
9+
"dev": "node scripts/fetch-widget-assets.js && astro dev",
1010
"preview": "astro preview",
1111
"start": "astro dev",
1212
"postbuild": "cp _headers ./dist/",
1313
"lint": "eslint .",
14-
"lint:fix": "eslint . --fix"
14+
"lint:fix": "eslint . --fix",
15+
"prebuild": "node scripts/fetch-widget-assets.js"
1516
},
1617
"dependencies": {
1718
"@astrojs/vue": "^5.1.0",
@@ -38,6 +39,7 @@
3839
"eslint-plugin-format": "^1.0.1",
3940
"fast-glob": "^3.3.3",
4041
"nimiq-css": "1.0.0-beta.54",
42+
"pathe": "^2.0.3",
4143
"prettier-plugin-astro": "^0.14.1",
4244
"typescript": "^5.4.5"
4345
}

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
259 KB
Binary file not shown.
205 KB
Binary file not shown.

public/widget.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/widget.js

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/fetch-widget-assets.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// ESM version: Fetch Nimiq Feedback Widget assets using fetch and pathe
2+
// Usage: node scripts/fetch-widget-assets.js
3+
4+
import fs from 'node:fs/promises'
5+
import { fileURLToPath } from 'node:url'
6+
import { dirname, join } from 'pathe'
7+
8+
const __filename = fileURLToPath(import.meta.url)
9+
const __dirname = dirname(__filename)
10+
11+
const files = [
12+
{
13+
url: 'https://nimiq-feedback.je-cf9.workers.dev/widget.css',
14+
dest: join(__dirname, '../public/widget.css'),
15+
},
16+
{
17+
url: 'https://nimiq-feedback.je-cf9.workers.dev/widget.js',
18+
dest: join(__dirname, '../public/widget.js'),
19+
},
20+
]
21+
22+
for (const { url, dest } of files) {
23+
try {
24+
const res = await fetch(url)
25+
if (!res.ok)
26+
throw new Error(`Failed to fetch ${url}: ${res.status}`)
27+
const buf = Buffer.from(await res.arrayBuffer())
28+
await fs.writeFile(dest, buf)
29+
console.log(`✅ Downloaded ${url}${dest}`)
30+
}
31+
catch (err) {
32+
console.error(`❌ Failed to download ${url}:`, err.message)
33+
}
34+
}

src/components/CustomHeadLinks.astro

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
<slot name="meta" />
44

55
<!-- Nimiq Feedback Widget CSS/JS -->
6-
<link rel="preload" href="https://nimiq-feedback.je-cf9.workers.dev/widget.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
7-
<noscript><link rel="stylesheet" href="https://nimiq-feedback.je-cf9.workers.dev/widget.css"></noscript>
8-
<script src="https://nimiq-feedback.je-cf9.workers.dev/widget.js" defer></script>
6+
<link rel="preload" href="/widget.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
7+
<noscript><link rel="stylesheet" href="/widget.css" /></noscript>
8+
<script src="/widget.js" defer></script>

src/components/FeedbackModal.vue

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { WidgetInstance } from '../types/feedback-widget'
33
import {
44
DialogClose,
55
DialogContent,
6-
DialogDescription,
76
DialogOverlay,
87
DialogPortal,
98
DialogRoot,
@@ -16,6 +15,7 @@ const widgetContainer = ref<HTMLDivElement>()
1615
const isWidgetLoaded = ref(false)
1716
const widgetInstance = ref<WidgetInstance>()
1817
const showFallbackForm = ref(false)
18+
const showSuccessMessage = ref(false)
1919
2020
const open = ref(false)
2121
@@ -37,7 +37,11 @@ async function mountWidget() {
3737
})
3838
widgetInstance.value.communication?.on('form-submitted', (data) => {
3939
console.log('Feedback submitted successfully:', data)
40-
setTimeout(() => open.value = false, 2000)
40+
showSuccessMessage.value = true
41+
setTimeout(() => {
42+
showSuccessMessage.value = false
43+
open.value = false
44+
}, 2000)
4145
})
4246
widgetInstance.value.communication?.on('form-error', (error) => {
4347
console.error('Feedback submission error:', error)
@@ -72,6 +76,7 @@ watch(open, async (newValue) => {
7276
if (newValue) {
7377
document.body.style.overflow = 'hidden'
7478
showFallbackForm.value = false
79+
showSuccessMessage.value = false
7580
try {
7681
await mountWidget()
7782
}
@@ -108,34 +113,38 @@ onUnmounted(() => {
108113
@open-auto-focus.prevent
109114
>
110115
<div class="relative bg-white py-8 ring-1 ring-neutral-200 dark:bg-neutral-900 dark:ring-neutral-800">
111-
<DialogTitle class="mb-3 px-6 text-center text-2xl text-neutral-900 font-bold leading-none lg:px-10 dark:text-neutral" as="h2">
116+
<DialogTitle class="sr-only mb-3 px-6 text-center text-2xl text-neutral-900 font-bold leading-none lg:px-10 dark:text-neutral" as="h2">
112117
Share Your Feedback
113118
</DialogTitle>
114119

115-
<DialogDescription class="block px-6 text-center text-neutral-700 lg:px-10 dark:text-neutral-400">
116-
Help us improve the Nimiq Tutorial by sharing your thoughts, reporting bugs, or suggesting new tutorials.
117-
</DialogDescription>
118-
119120
<div class="mt-3 px-6 lg:px-10">
120121
<!-- Loading state -->
121-
<div v-if="!isWidgetLoaded && !showFallbackForm" class="h-64 flex items-center justify-center">
122+
<div v-if="!isWidgetLoaded && !showFallbackForm && !showSuccessMessage" class="h-64 flex items-center justify-center">
122123
<div class="flex items-center text-neutral-500 space-x-2 dark:text-neutral-400">
123-
<div class="i-nimiq:spinner h-5 w-5" />
124+
<div class="i-ph:spinner h-5 w-5" />
124125
<span>Loading feedback form...</span>
125126
</div>
126127
</div>
127128

129+
<!-- Success state -->
130+
<div v-if="showSuccessMessage" class="h-64 flex flex-col items-center justify-center space-y-4">
131+
<div class="i-ph:check-circle h-12 w-12 text-green-500" />
132+
<div class="text-lg text-green-600 font-medium dark:text-green-400">
133+
Thank you for your feedback!
134+
</div>
135+
</div>
136+
128137
<!-- External Widget -->
129138
<div
130139
id="feedback-widget"
131140
ref="widgetContainer"
132-
:class="{ block: isWidgetLoaded, hidden: !isWidgetLoaded }"
141+
:class="{ block: isWidgetLoaded && !showSuccessMessage, hidden: !isWidgetLoaded || showSuccessMessage }"
133142
/>
134143

135144
<!-- Error state -->
136145
<div v-if="showFallbackForm && !isWidgetLoaded" class="h-64 flex items-center justify-center">
137146
<div class="text-center space-y-4">
138-
<div class="i-nimiq:warning mx-auto h-12 w-12 text-yellow-500" />
147+
<div class="i-ph:warning-circle mx-auto h-12 w-12 text-yellow-500" />
139148
<div class="text-neutral-500 dark:text-neutral-400">
140149
Unable to load feedback form
141150
</div>
@@ -156,7 +165,7 @@ onUnmounted(() => {
156165
class="absolute right-4 top-4 cursor-pointer transition-colors hover:text-neutral-600 dark:hover:text-neutral-300"
157166
aria-label="Close"
158167
>
159-
<div class="i-nimiq:cross h-6 w-6" />
168+
<div class="i-ph:x h-6 w-6" />
160169
</DialogClose>
161170
</div>
162171
</DialogContent>

theme.css

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,30 @@
22
@import './node_modules/nimiq-css/dist/css/colors.css';
33
@import './node_modules/nimiq-css/dist/css/fonts.css';
44

5+
/* Add Mulish Variable Font (local) */
6+
@font-face {
7+
font-family: 'Mulish';
8+
src: url('/assets/fonts/Mulish-VariableFont_wght.ttf') format('truetype');
9+
font-weight: 100 900;
10+
font-display: swap;
11+
}
12+
13+
/* Add Fira Code from Google Fonts */
14+
@font-face {
15+
font-family: 'Fira Code';
16+
src: url('/assets/fonts/FiraCode-VariableFont_wght.ttf') format('truetype');
17+
font-weight: 400 700;
18+
font-display: swap;
19+
}
20+
521
/* TutorialKit Theme using Nimiq Design System */
622
:root,
723
:root[data-theme='light'] {
824
/* High-level app styling */
925
--tk-elements-app-textColor: var(--colors-neutral);
1026
--tk-elements-app-backgroundColor: var(--colors-neutral-0);
1127
--tk-elements-app-borderColor: var(--colors-neutral-300);
12-
28+
1329
/* Background tokens */
1430
--tk-background-primary: var(--colors-neutral-0);
1531
--tk-background-secondary: var(--colors-neutral-200);
@@ -138,6 +154,15 @@
138154
--tk-terminal-background: var(--colors-darkblue);
139155
}
140156

157+
.markdown-content :where(h1, h2, h3, h4) {
158+
--heading-font-weight: 700;
159+
}
160+
161+
:where(:not(:where(.nq-raw *, [nq-raw] *))):where(p, span):empty {
162+
display: inherit !important;
163+
}
164+
165+
141166
/* Custom styling for Nimiq branding touches */
142167
.tk-topbar {
143168
background: var(--colors-neutral-gradient);
@@ -178,6 +203,7 @@
178203
:root {
179204
font-family:
180205
'Muli',
206+
'Mulish'
181207
'Inter',
182208
system-ui,
183209
-apple-system,
@@ -191,3 +217,13 @@ div[role='separator']:hover::after {
191217
background-color: color-mix(in srgb, var(--colors-neutral-0) 8%, transparent);
192218
}
193219
}
220+
221+
.cm-editor * {
222+
font-family: 'Fira Code', monospace;
223+
font-size: 0.8rem;
224+
}
225+
226+
.terminal * {
227+
letter-spacing: normal !important;
228+
font-family: 'Fira Code', monospace;
229+
}

0 commit comments

Comments
 (0)