@fullstackdatasolutions/articles 0.6.0 → 0.7.1

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/dist/index.js CHANGED
@@ -966,19 +966,10 @@ function ArticleSocialShare({ title, url, excerpt, shareMessage }) {
966
966
  /* @__PURE__ */ jsx12(MessageCircle, { className: "h-4 w-4" }),
967
967
  "Telegram"
968
968
  ] }),
969
- /* @__PURE__ */ jsxs12(
970
- "button",
971
- {
972
- className: btnClass,
973
- onClick: () => {
974
- globalThis.location.href = shareLinks.email;
975
- },
976
- children: [
977
- /* @__PURE__ */ jsx12(Mail, { className: "h-4 w-4" }),
978
- "Email"
979
- ]
980
- }
981
- ),
969
+ /* @__PURE__ */ jsxs12("a", { className: btnClass, href: shareLinks.email, children: [
970
+ /* @__PURE__ */ jsx12(Mail, { className: "h-4 w-4" }),
971
+ "Email"
972
+ ] }),
982
973
  /* @__PURE__ */ jsxs12("button", { className: btnClass, onClick: copyToClipboard, children: [
983
974
  copied ? /* @__PURE__ */ jsx12(Check, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx12(Copy, { className: "h-4 w-4" }),
984
975
  copied ? "Copied!" : "Copy Link"
@@ -1029,18 +1020,42 @@ function ArticleNavigation({ previous, next, basePath }) {
1029
1020
  ] }) });
1030
1021
  }
1031
1022
 
1032
- // src/ArticleTOC.tsx
1023
+ // src/ArticleBackLink.tsx
1024
+ import Link8 from "next/link";
1025
+ import { ArrowLeft } from "lucide-react";
1033
1026
  import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
1027
+ function ArticleBackLink({
1028
+ config,
1029
+ href = "/articles",
1030
+ label = "Back to Articles",
1031
+ className
1032
+ }) {
1033
+ if (config.showBackToArticles === false) return null;
1034
+ return /* @__PURE__ */ jsxs14(
1035
+ Link8,
1036
+ {
1037
+ href,
1038
+ className: className != null ? className : "inline-flex items-center gap-2 mb-6 -ml-3 px-3 py-2 rounded-md text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors",
1039
+ children: [
1040
+ /* @__PURE__ */ jsx14(ArrowLeft, { className: "h-4 w-4" }),
1041
+ label
1042
+ ]
1043
+ }
1044
+ );
1045
+ }
1046
+
1047
+ // src/ArticleTOC.tsx
1048
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
1034
1049
  function ArticleTOC({ toc, className }) {
1035
1050
  if (!toc.length) return null;
1036
- return /* @__PURE__ */ jsxs14(
1051
+ return /* @__PURE__ */ jsxs15(
1037
1052
  "nav",
1038
1053
  {
1039
1054
  "aria-label": "Table of contents",
1040
1055
  className: `mb-8 rounded-lg border border-border bg-muted/40 px-6 py-4 ${className != null ? className : ""}`,
1041
1056
  children: [
1042
- /* @__PURE__ */ jsx14("p", { className: "mb-3 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: "On this page" }),
1043
- /* @__PURE__ */ jsx14("ul", { className: "space-y-1 text-sm", children: toc.map((item) => /* @__PURE__ */ jsx14("li", { style: { paddingLeft: `${Math.max(0, item.depth - 2) * 1}rem` }, children: /* @__PURE__ */ jsx14(
1057
+ /* @__PURE__ */ jsx15("p", { className: "mb-3 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: "On this page" }),
1058
+ /* @__PURE__ */ jsx15("ul", { className: "space-y-1 text-sm", children: toc.map((item) => /* @__PURE__ */ jsx15("li", { style: { paddingLeft: `${Math.max(0, item.depth - 2) * 1}rem` }, children: /* @__PURE__ */ jsx15(
1044
1059
  "a",
1045
1060
  {
1046
1061
  href: `#${item.id}`,
@@ -1056,7 +1071,7 @@ function ArticleTOC({ toc, className }) {
1056
1071
  // src/ScrollToTop.tsx
1057
1072
  import { useEffect as useEffect4, useState as useState5 } from "react";
1058
1073
  import { ArrowUp } from "lucide-react";
1059
- import { jsx as jsx15 } from "react/jsx-runtime";
1074
+ import { jsx as jsx16 } from "react/jsx-runtime";
1060
1075
  function ScrollToTop() {
1061
1076
  const [visible, setVisible] = useState5(false);
1062
1077
  useEffect4(() => {
@@ -1065,13 +1080,13 @@ function ScrollToTop() {
1065
1080
  return () => globalThis.removeEventListener("scroll", onScroll);
1066
1081
  }, []);
1067
1082
  if (!visible) return null;
1068
- return /* @__PURE__ */ jsx15(
1083
+ return /* @__PURE__ */ jsx16(
1069
1084
  "button",
1070
1085
  {
1071
1086
  "aria-label": "Scroll to top",
1072
1087
  onClick: () => globalThis.scrollTo({ top: 0, behavior: "smooth" }),
1073
1088
  className: "fixed bottom-8 right-8 z-50 rounded-full bg-primary p-2 shadow-md text-primary-foreground hover:bg-primary/90 transition-colors",
1074
- children: /* @__PURE__ */ jsx15(ArrowUp, { className: "h-5 w-5" })
1089
+ children: /* @__PURE__ */ jsx16(ArrowUp, { className: "h-5 w-5" })
1075
1090
  }
1076
1091
  );
1077
1092
  }
@@ -1082,7 +1097,7 @@ import { useCallback as useCallback2, useEffect as useEffect5, useState as useSt
1082
1097
 
1083
1098
  // src/CommentForm.tsx
1084
1099
  import { useState as useState6 } from "react";
1085
- import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1100
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1086
1101
  var MAX_LENGTH = 2e3;
1087
1102
  var WARN_THRESHOLD = 1800;
1088
1103
  function submitLabel(submitting, parentId) {
@@ -1121,8 +1136,8 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
1121
1136
  }
1122
1137
  });
1123
1138
  }
1124
- return /* @__PURE__ */ jsxs15("form", { onSubmit: handleSubmit, className: "space-y-2", children: [
1125
- /* @__PURE__ */ jsx16(
1139
+ return /* @__PURE__ */ jsxs16("form", { onSubmit: handleSubmit, className: "space-y-2", children: [
1140
+ /* @__PURE__ */ jsx17(
1126
1141
  "textarea",
1127
1142
  {
1128
1143
  value: body,
@@ -1135,13 +1150,13 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
1135
1150
  "aria-label": parentId ? "Reply text" : "Comment text"
1136
1151
  }
1137
1152
  ),
1138
- remaining <= MAX_LENGTH - WARN_THRESHOLD && /* @__PURE__ */ jsxs15("p", { className: `text-xs ${remaining < 0 ? "text-destructive" : "text-muted-foreground"}`, children: [
1153
+ remaining <= MAX_LENGTH - WARN_THRESHOLD && /* @__PURE__ */ jsxs16("p", { className: `text-xs ${remaining < 0 ? "text-destructive" : "text-muted-foreground"}`, children: [
1139
1154
  remaining,
1140
1155
  " characters remaining"
1141
1156
  ] }),
1142
- error && /* @__PURE__ */ jsx16("p", { className: "text-xs text-destructive", children: error }),
1143
- /* @__PURE__ */ jsxs15("div", { className: "flex gap-2", children: [
1144
- /* @__PURE__ */ jsx16(
1157
+ error && /* @__PURE__ */ jsx17("p", { className: "text-xs text-destructive", children: error }),
1158
+ /* @__PURE__ */ jsxs16("div", { className: "flex gap-2", children: [
1159
+ /* @__PURE__ */ jsx17(
1145
1160
  "button",
1146
1161
  {
1147
1162
  type: "submit",
@@ -1150,7 +1165,7 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
1150
1165
  children: submitLabel(submitting, parentId)
1151
1166
  }
1152
1167
  ),
1153
- onCancel && /* @__PURE__ */ jsx16(
1168
+ onCancel && /* @__PURE__ */ jsx17(
1154
1169
  "button",
1155
1170
  {
1156
1171
  type: "button",
@@ -1165,7 +1180,7 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
1165
1180
 
1166
1181
  // src/CommentItem.tsx
1167
1182
  import { useState as useState7 } from "react";
1168
- import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1183
+ import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
1169
1184
  function relativeTime(iso) {
1170
1185
  const diff = Date.now() - new Date(iso).getTime();
1171
1186
  const minutes = Math.floor(diff / 6e4);
@@ -1203,15 +1218,15 @@ function CommentItem({
1203
1218
  }
1204
1219
  });
1205
1220
  }
1206
- return /* @__PURE__ */ jsxs16("div", { className: `${isReply ? "ml-8 border-l-2 border-border pl-4" : ""}`, children: [
1207
- /* @__PURE__ */ jsx17("div", { className: "rounded-lg bg-muted/40 p-3 space-y-1", children: comment.isDeleted ? /* @__PURE__ */ jsx17("p", { className: "text-sm italic text-muted-foreground", children: "Comment removed" }) : /* @__PURE__ */ jsxs16(Fragment2, { children: [
1208
- /* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-between gap-2", children: [
1209
- /* @__PURE__ */ jsx17("span", { className: "text-sm font-medium text-foreground", children: comment.authorName }),
1210
- /* @__PURE__ */ jsx17("span", { className: "text-xs text-muted-foreground", children: relativeTime(comment.createdAt) })
1221
+ return /* @__PURE__ */ jsxs17("div", { className: `${isReply ? "ml-8 border-l-2 border-border pl-4" : ""}`, children: [
1222
+ /* @__PURE__ */ jsx18("div", { className: "rounded-lg bg-muted/40 p-3 space-y-1", children: comment.isDeleted ? /* @__PURE__ */ jsx18("p", { className: "text-sm italic text-muted-foreground", children: "Comment removed" }) : /* @__PURE__ */ jsxs17(Fragment2, { children: [
1223
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-center justify-between gap-2", children: [
1224
+ /* @__PURE__ */ jsx18("span", { className: "text-sm font-medium text-foreground", children: comment.authorName }),
1225
+ /* @__PURE__ */ jsx18("span", { className: "text-xs text-muted-foreground", children: relativeTime(comment.createdAt) })
1211
1226
  ] }),
1212
- /* @__PURE__ */ jsx17("p", { className: "text-sm text-foreground whitespace-pre-wrap break-words", children: comment.body }),
1213
- /* @__PURE__ */ jsxs16("div", { className: "flex gap-3 pt-1", children: [
1214
- canReply && /* @__PURE__ */ jsx17(
1227
+ /* @__PURE__ */ jsx18("p", { className: "text-sm text-foreground whitespace-pre-wrap break-words", children: comment.body }),
1228
+ /* @__PURE__ */ jsxs17("div", { className: "flex gap-3 pt-1", children: [
1229
+ canReply && /* @__PURE__ */ jsx18(
1215
1230
  "button",
1216
1231
  {
1217
1232
  onClick: () => setShowReplyForm((v) => !v),
@@ -1219,7 +1234,7 @@ function CommentItem({
1219
1234
  children: showReplyForm ? "Cancel" : "Reply"
1220
1235
  }
1221
1236
  ),
1222
- canDelete && /* @__PURE__ */ jsx17(
1237
+ canDelete && /* @__PURE__ */ jsx18(
1223
1238
  "button",
1224
1239
  {
1225
1240
  onClick: handleDelete,
@@ -1230,7 +1245,7 @@ function CommentItem({
1230
1245
  )
1231
1246
  ] })
1232
1247
  ] }) }),
1233
- showReplyForm && /* @__PURE__ */ jsx17("div", { className: "mt-2 ml-2", children: /* @__PURE__ */ jsx17(
1248
+ showReplyForm && /* @__PURE__ */ jsx18("div", { className: "mt-2 ml-2", children: /* @__PURE__ */ jsx18(
1234
1249
  CommentForm,
1235
1250
  {
1236
1251
  articleSlug,
@@ -1242,7 +1257,7 @@ function CommentItem({
1242
1257
  onCancel: () => setShowReplyForm(false)
1243
1258
  }
1244
1259
  ) }),
1245
- replies.length > 0 && /* @__PURE__ */ jsx17("div", { className: "mt-2 space-y-2", children: replies.map((reply) => /* @__PURE__ */ jsx17(
1260
+ replies.length > 0 && /* @__PURE__ */ jsx18("div", { className: "mt-2 space-y-2", children: replies.map((reply) => /* @__PURE__ */ jsx18(
1246
1261
  CommentItem,
1247
1262
  {
1248
1263
  comment: __spreadProps(__spreadValues({}, reply), { replies: [] }),
@@ -1257,7 +1272,7 @@ function CommentItem({
1257
1272
  }
1258
1273
 
1259
1274
  // src/CommentThread.tsx
1260
- import { jsx as jsx18 } from "react/jsx-runtime";
1275
+ import { jsx as jsx19 } from "react/jsx-runtime";
1261
1276
  function CommentThread({
1262
1277
  comments,
1263
1278
  articleSlug,
@@ -1265,9 +1280,9 @@ function CommentThread({
1265
1280
  onRefresh
1266
1281
  }) {
1267
1282
  if (comments.length === 0) {
1268
- return /* @__PURE__ */ jsx18("p", { className: "text-sm text-muted-foreground text-center py-6", children: "No comments yet. Be the first to share your thoughts." });
1283
+ return /* @__PURE__ */ jsx19("p", { className: "text-sm text-muted-foreground text-center py-6", children: "No comments yet. Be the first to share your thoughts." });
1269
1284
  }
1270
- return /* @__PURE__ */ jsx18("div", { className: "space-y-4", children: comments.map((comment) => /* @__PURE__ */ jsx18(
1285
+ return /* @__PURE__ */ jsx19("div", { className: "space-y-4", children: comments.map((comment) => /* @__PURE__ */ jsx19(
1271
1286
  CommentItem,
1272
1287
  {
1273
1288
  comment,
@@ -1280,7 +1295,7 @@ function CommentThread({
1280
1295
  }
1281
1296
 
1282
1297
  // src/CommentsSection.tsx
1283
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
1298
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
1284
1299
  function CommentsSection({ articleSlug, config }) {
1285
1300
  var _a, _b, _c, _d, _e, _f;
1286
1301
  const { data: session, status } = useSession();
@@ -1312,10 +1327,10 @@ function CommentsSection({ articleSlug, config }) {
1312
1327
  if (!enabled) return null;
1313
1328
  const count = comments.length;
1314
1329
  const label = count === 1 ? "1 comment" : `${count} comments`;
1315
- return /* @__PURE__ */ jsxs17("section", { "aria-label": "Comments", className: "mt-12 pt-8 border-t border-border space-y-6", children: [
1316
- /* @__PURE__ */ jsx19("h2", { className: "text-xl font-semibold text-foreground", children: loading ? "Comments" : label }),
1317
- status === "authenticated" ? /* @__PURE__ */ jsx19(CommentForm, { articleSlug, onSuccess: fetchComments }) : /* @__PURE__ */ jsxs17("p", { className: "text-sm text-muted-foreground", children: [
1318
- /* @__PURE__ */ jsx19(
1330
+ return /* @__PURE__ */ jsxs18("section", { "aria-label": "Comments", className: "mt-12 pt-8 border-t border-border space-y-6", children: [
1331
+ /* @__PURE__ */ jsx20("h2", { className: "text-xl font-semibold text-foreground", children: loading ? "Comments" : label }),
1332
+ status === "authenticated" ? /* @__PURE__ */ jsx20(CommentForm, { articleSlug, onSuccess: fetchComments }) : /* @__PURE__ */ jsxs18("p", { className: "text-sm text-muted-foreground", children: [
1333
+ /* @__PURE__ */ jsx20(
1319
1334
  "button",
1320
1335
  {
1321
1336
  onClick: () => signIn(),
@@ -1326,8 +1341,8 @@ function CommentsSection({ articleSlug, config }) {
1326
1341
  " ",
1327
1342
  "to join the discussion."
1328
1343
  ] }),
1329
- fetchError && /* @__PURE__ */ jsx19("p", { className: "text-sm text-destructive", children: fetchError }),
1330
- loading ? /* @__PURE__ */ jsx19("p", { className: "text-sm text-muted-foreground", children: "Loading comments\u2026" }) : /* @__PURE__ */ jsx19(
1344
+ fetchError && /* @__PURE__ */ jsx20("p", { className: "text-sm text-destructive", children: fetchError }),
1345
+ loading ? /* @__PURE__ */ jsx20("p", { className: "text-sm text-muted-foreground", children: "Loading comments\u2026" }) : /* @__PURE__ */ jsx20(
1331
1346
  CommentThread,
1332
1347
  {
1333
1348
  comments,
@@ -1339,6 +1354,7 @@ function CommentsSection({ articleSlug, config }) {
1339
1354
  ] });
1340
1355
  }
1341
1356
  export {
1357
+ ArticleBackLink,
1342
1358
  ArticleCard,
1343
1359
  ArticleCategoryGrid,
1344
1360
  ArticleDetailHero,