@farming-labs/astro-theme 0.0.51 → 0.0.53

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/astro-theme",
3
- "version": "0.0.51",
3
+ "version": "0.0.53",
4
4
  "description": "Astro UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
5
5
  "keywords": [
6
6
  "astro",
@@ -79,8 +79,8 @@
79
79
  },
80
80
  "dependencies": {
81
81
  "sugar-high": "^0.9.5",
82
- "@farming-labs/astro": "0.0.51",
83
- "@farming-labs/docs": "0.0.51"
82
+ "@farming-labs/docs": "0.0.53",
83
+ "@farming-labs/astro": "0.0.53"
84
84
  },
85
85
  "peerDependencies": {
86
86
  "astro": ">=4.0.0"
@@ -97,6 +97,25 @@ const lastUpdatedConfig = (() => {
97
97
 
98
98
  const showLastUpdatedInFooter = !!data.lastModified && lastUpdatedConfig.enabled && lastUpdatedConfig.position === "footer";
99
99
  const showLastUpdatedBelowTitle = !!data.lastModified && lastUpdatedConfig.enabled && lastUpdatedConfig.position === "below-title";
100
+ const feedbackConfig = (() => {
101
+ const defaults = {
102
+ enabled: false,
103
+ question: "How is this guide?",
104
+ positiveLabel: "Good",
105
+ negativeLabel: "Bad",
106
+ };
107
+ const feedback = config?.feedback;
108
+ if (feedback === undefined || feedback === false) return defaults;
109
+ if (feedback === true) return { ...defaults, enabled: true };
110
+ if (typeof feedback !== "object" || feedback === null) return defaults;
111
+ return {
112
+ enabled: feedback.enabled !== false,
113
+ question: feedback.question ?? defaults.question,
114
+ positiveLabel: feedback.positiveLabel ?? defaults.positiveLabel,
115
+ negativeLabel: feedback.negativeLabel ?? defaults.negativeLabel,
116
+ };
117
+ })();
118
+ const feedbackEntry = data.entry ?? config?.entry ?? "docs";
100
119
 
101
120
  const htmlWithoutFirstH1 = (data.html || "").replace(/<h1[^>]*>[\s\S]*?<\/h1>\s*/i, "");
102
121
  ---
@@ -221,14 +240,75 @@ const htmlWithoutFirstH1 = (data.html || "").replace(/<h1[^>]*>[\s\S]*?<\/h1>\s*
221
240
  </>
222
241
  )}
223
242
  <Fragment set:html={htmlWithoutFirstH1} />
243
+ {feedbackConfig.enabled && (
244
+ <section class="fd-feedback" aria-label="Page feedback">
245
+ <div class="fd-feedback-content">
246
+ <p class="fd-feedback-question">{feedbackConfig.question}</p>
247
+ <div class="fd-feedback-actions" role="group" aria-label={feedbackConfig.question}>
248
+ <button
249
+ type="button"
250
+ class="fd-page-action-btn"
251
+ aria-pressed="false"
252
+ data-feedback-button
253
+ data-feedback-value="positive"
254
+ >
255
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" aria-hidden="true">
256
+ <path
257
+ d="M7 21H5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h2m0 11V10m0 11h9.28a2 2 0 0 0 1.97-1.66l1.2-7A2 2 0 0 0 17.48 10H13V6.5a2.5 2.5 0 0 0-2.5-2.5L7 10"
258
+ stroke="currentColor"
259
+ stroke-width="2"
260
+ stroke-linecap="round"
261
+ stroke-linejoin="round"
262
+ />
263
+ </svg>
264
+ <span>{feedbackConfig.positiveLabel}</span>
265
+ </button>
266
+ <button
267
+ type="button"
268
+ class="fd-page-action-btn"
269
+ aria-pressed="false"
270
+ data-feedback-button
271
+ data-feedback-value="negative"
272
+ >
273
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" aria-hidden="true">
274
+ <path
275
+ d="M17 3h2a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-2M17 3v11m0-11H7.72a2 2 0 0 0-1.97 1.66l-1.2 7A2 2 0 0 0 6.52 14H11v3.5a2.5 2.5 0 0 0 2.5 2.5L17 14"
276
+ stroke="currentColor"
277
+ stroke-width="2"
278
+ stroke-linecap="round"
279
+ stroke-linejoin="round"
280
+ />
281
+ </svg>
282
+ <span>{feedbackConfig.negativeLabel}</span>
283
+ </button>
284
+ </div>
285
+ </div>
286
+ </section>
287
+ )}
224
288
  </DocsPage>
225
289
 
226
- {(copyMarkdownEnabled || openDocsEnabled) && (
227
- <script define:vars={{ pathname, openDocsProviders, githubFileUrl }}>
290
+ {(copyMarkdownEnabled || openDocsEnabled || feedbackConfig.enabled) && (
291
+ <script
292
+ define:vars={{
293
+ pathname,
294
+ openDocsProviders,
295
+ githubFileUrl,
296
+ feedbackEntry,
297
+ feedbackLocale: data.locale ?? null,
298
+ feedbackSlug: data.slug ?? "",
299
+ feedbackTitle: data.title,
300
+ feedbackDescription: data.description ?? null,
301
+ }}
302
+ >
228
303
  (function () {
229
304
  var pathnameVal = typeof pathname === "string" ? pathname : "";
230
305
  var providers = Array.isArray(openDocsProviders) ? openDocsProviders : [];
231
306
  var githubFileUrlVal = githubFileUrl || "";
307
+ var feedbackEntryVal = typeof feedbackEntry === "string" ? feedbackEntry : "docs";
308
+ var feedbackLocaleVal = typeof feedbackLocale === "string" ? feedbackLocale : undefined;
309
+ var feedbackSlugVal = typeof feedbackSlug === "string" ? feedbackSlug : "";
310
+ var feedbackTitleVal = typeof feedbackTitle === "string" ? feedbackTitle : undefined;
311
+ var feedbackDescriptionVal = typeof feedbackDescription === "string" ? feedbackDescription : undefined;
232
312
 
233
313
  function init() {
234
314
  document.querySelectorAll("[data-copy-page]").forEach(function (btn) {
@@ -299,6 +379,44 @@ const htmlWithoutFirstH1 = (data.html || "").replace(/<h1[^>]*>[\s\S]*?<\/h1>\s*
299
379
  if (triggerEl) triggerEl.setAttribute("aria-expanded", "false");
300
380
  });
301
381
  });
382
+
383
+ document.querySelectorAll("[data-feedback-button]").forEach(function (btn) {
384
+ btn.addEventListener("click", function () {
385
+ var value = btn.getAttribute("data-feedback-value");
386
+ if (value !== "positive" && value !== "negative") return;
387
+
388
+ document.querySelectorAll("[data-feedback-button]").forEach(function (item) {
389
+ if (!(item instanceof HTMLElement)) return;
390
+ var selected = item.getAttribute("data-feedback-value") === value;
391
+ if (selected) item.setAttribute("data-selected", "true");
392
+ else item.removeAttribute("data-selected");
393
+ item.setAttribute("aria-pressed", String(selected));
394
+ });
395
+
396
+ var pathnameCurrent = window.location.pathname.replace(/\/$/, "") || "/";
397
+ var data = {
398
+ value: value,
399
+ title: feedbackTitleVal,
400
+ description: feedbackDescriptionVal,
401
+ url: window.location.href,
402
+ pathname: pathnameCurrent,
403
+ path: pathnameCurrent,
404
+ entry: feedbackEntryVal,
405
+ slug: feedbackSlugVal,
406
+ locale: feedbackLocaleVal,
407
+ };
408
+
409
+ try {
410
+ if (typeof window !== "undefined" && window.__fdOnFeedback__) {
411
+ window.__fdOnFeedback__(data);
412
+ }
413
+ } catch (_) {}
414
+
415
+ if (typeof window !== "undefined") {
416
+ window.dispatchEvent(new CustomEvent("fd:feedback", { detail: data }));
417
+ }
418
+ });
419
+ });
302
420
  }
303
421
 
304
422
  if (document.readyState === "loading") {
package/styles/docs.css CHANGED
@@ -701,10 +701,19 @@ samp {
701
701
  color: var(--color-fd-foreground);
702
702
  }
703
703
 
704
+ .fd-page-action-btn[data-selected="true"] {
705
+ color: var(--color-fd-accent-foreground);
706
+ background: var(--color-fd-accent);
707
+ }
708
+
704
709
  .fd-page-action-btn svg {
705
710
  flex-shrink: 0;
706
711
  }
707
712
 
713
+ .fd-page-action-btn[data-selected="true"] svg {
714
+ color: currentColor;
715
+ }
716
+
708
717
  .fd-page-action-dropdown {
709
718
  position: relative;
710
719
  }
@@ -1611,6 +1620,35 @@ html.dark pre.shiki {
1611
1620
  margin-bottom: 1rem;
1612
1621
  }
1613
1622
 
1623
+ .fd-feedback {
1624
+ margin-top: 2rem;
1625
+ padding-top: 1.25rem;
1626
+ border-top: 1px solid var(--color-fd-border);
1627
+ }
1628
+
1629
+ .fd-feedback-content {
1630
+ display: flex;
1631
+ align-items: center;
1632
+ justify-content: space-between;
1633
+ gap: 1rem;
1634
+ flex-wrap: wrap;
1635
+ }
1636
+
1637
+ .fd-feedback-question {
1638
+ margin: 0;
1639
+ font-size: 0.9375rem;
1640
+ font-weight: 600;
1641
+ line-height: 1.5;
1642
+ color: var(--color-fd-foreground);
1643
+ }
1644
+
1645
+ .fd-feedback-actions {
1646
+ display: inline-flex;
1647
+ align-items: center;
1648
+ gap: 0.5rem;
1649
+ flex-wrap: wrap;
1650
+ }
1651
+
1614
1652
  @media (max-width: 640px) {
1615
1653
  .fd-last-modified {
1616
1654
  width: 100%;