@reblu/site-blocks 0.20.0 → 0.22.0
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/CHANGELOG.md +35 -0
- package/README.md +209 -14
- package/dist/client.cjs +218 -83
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +40 -13
- package/dist/client.d.ts +40 -13
- package/dist/client.js +221 -86
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +620 -321
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -2
- package/dist/index.d.ts +144 -2
- package/dist/index.js +614 -321
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/client.cjs
CHANGED
|
@@ -763,42 +763,104 @@ var DEFAULT_COURSE_SYLLABUS_LABELS = {
|
|
|
763
763
|
lessonPlural: "lecciones",
|
|
764
764
|
freePreview: "Vista previa gratuita",
|
|
765
765
|
hours: "h",
|
|
766
|
-
minutes: "min"
|
|
766
|
+
minutes: "min",
|
|
767
|
+
expandAll: "Expandir todo",
|
|
768
|
+
collapseAll: "Contraer todo",
|
|
769
|
+
videoLesson: "V\xEDdeo",
|
|
770
|
+
textLesson: "Lectura"
|
|
767
771
|
};
|
|
768
772
|
var SEPARATOR = " \xB7 ";
|
|
769
773
|
function count(n, singular, plural) {
|
|
770
774
|
return `${n} ${n === 1 ? singular : plural}`;
|
|
771
775
|
}
|
|
772
|
-
function
|
|
776
|
+
function formatTotal(seconds, labels) {
|
|
773
777
|
const totalMinutes = Math.max(1, Math.round(seconds / 60));
|
|
774
778
|
const hours = Math.floor(totalMinutes / 60);
|
|
775
779
|
const minutes = totalMinutes % 60;
|
|
776
780
|
if (hours === 0) return `${minutes} ${labels.minutes}`;
|
|
777
781
|
return minutes === 0 ? `${hours} ${labels.hours}` : `${hours} ${labels.hours} ${minutes} ${labels.minutes}`;
|
|
778
782
|
}
|
|
779
|
-
function
|
|
783
|
+
function splitSeconds(seconds) {
|
|
784
|
+
const whole = Math.round(seconds);
|
|
785
|
+
return [Math.floor(whole / 3600), Math.floor(whole % 3600 / 60), whole % 60];
|
|
786
|
+
}
|
|
787
|
+
function formatClock(seconds) {
|
|
788
|
+
const [h, m, s] = splitSeconds(seconds);
|
|
789
|
+
const ss = String(s).padStart(2, "0");
|
|
790
|
+
return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${ss}` : `${m}:${ss}`;
|
|
791
|
+
}
|
|
792
|
+
function isoDuration(seconds) {
|
|
793
|
+
const [h, m, s] = splitSeconds(seconds);
|
|
794
|
+
return `PT${h > 0 ? `${h}H` : ""}${m}M${s}S`;
|
|
795
|
+
}
|
|
796
|
+
function hasDuration(lesson) {
|
|
797
|
+
return typeof lesson.durationSeconds === "number" && lesson.durationSeconds > 0;
|
|
798
|
+
}
|
|
799
|
+
function totalSeconds(lessons) {
|
|
800
|
+
if (lessons.length === 0) return null;
|
|
780
801
|
let total = 0;
|
|
781
802
|
for (const l of lessons) {
|
|
782
|
-
if (
|
|
803
|
+
if (!hasDuration(l)) return null;
|
|
783
804
|
total += l.durationSeconds;
|
|
784
805
|
}
|
|
785
806
|
return total;
|
|
786
807
|
}
|
|
808
|
+
function fillTemplate(template, lesson) {
|
|
809
|
+
return template.replaceAll("{lessonSlug}", encodeURIComponent(lesson.slug)).replaceAll("{lessonId}", encodeURIComponent(lesson.id));
|
|
810
|
+
}
|
|
811
|
+
var ICON_PROPS = {
|
|
812
|
+
"aria-hidden": true,
|
|
813
|
+
viewBox: "0 0 24 24",
|
|
814
|
+
fill: "none",
|
|
815
|
+
stroke: "currentColor",
|
|
816
|
+
strokeWidth: 2,
|
|
817
|
+
strokeLinecap: "round",
|
|
818
|
+
strokeLinejoin: "round"
|
|
819
|
+
};
|
|
820
|
+
function LessonIcon({ type }) {
|
|
821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
822
|
+
"svg",
|
|
823
|
+
{
|
|
824
|
+
...ICON_PROPS,
|
|
825
|
+
"data-slot": "course-syllabus-lesson-icon",
|
|
826
|
+
"data-type": type,
|
|
827
|
+
className: "size-4 shrink-0 text-muted-foreground",
|
|
828
|
+
children: type === "video" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
829
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "9" }),
|
|
830
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "m10 8.5 5 3.5-5 3.5z" })
|
|
831
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
832
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z" }),
|
|
833
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14 3v5h5M9 13h6M9 17h4" })
|
|
834
|
+
] })
|
|
835
|
+
}
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
function PlayIcon() {
|
|
839
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { ...ICON_PROPS, className: "size-3.5 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "m7 4 13 8-13 8z", fill: "currentColor" }) });
|
|
840
|
+
}
|
|
841
|
+
var PREVIEW_CTA = "inline-flex items-center gap-1.5 rounded-full border border-primary/40 bg-primary/10 px-3 py-1 text-xs font-semibold text-primary transition-colors hover:bg-primary hover:text-primary-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none";
|
|
787
842
|
function CourseSyllabus({
|
|
788
843
|
modules,
|
|
789
844
|
labels: labelOverrides,
|
|
790
845
|
headingLevel = 2,
|
|
791
846
|
headingClassName,
|
|
792
|
-
className
|
|
847
|
+
className,
|
|
848
|
+
getPreviewHref,
|
|
849
|
+
previewHrefTemplate,
|
|
850
|
+
onPreview
|
|
793
851
|
}) {
|
|
794
852
|
const labels = { ...DEFAULT_COURSE_SYLLABUS_LABELS, ...labelOverrides };
|
|
795
853
|
const baseId = (0, import_react5.useId)();
|
|
796
854
|
const [open, setOpen] = (0, import_react5.useState)(() => /* @__PURE__ */ new Set());
|
|
797
855
|
if (modules.length === 0) return null;
|
|
798
|
-
const
|
|
856
|
+
const expandable = modules.filter((m) => (m.lessons?.length ?? 0) > 0).map((m) => m.id);
|
|
857
|
+
const allLessons = modules.flatMap((m) => m.lessons ?? []);
|
|
858
|
+
const courseSeconds = totalSeconds(allLessons);
|
|
799
859
|
const summary = [count(modules.length, labels.moduleSingular, labels.modulePlural)];
|
|
800
|
-
if (
|
|
801
|
-
summary.push(count(
|
|
860
|
+
if (allLessons.length > 0)
|
|
861
|
+
summary.push(count(allLessons.length, labels.lessonSingular, labels.lessonPlural));
|
|
862
|
+
if (courseSeconds !== null) summary.push(formatTotal(courseSeconds, labels));
|
|
863
|
+
const allOpen = expandable.length > 0 && expandable.every((id) => open.has(id));
|
|
802
864
|
const headingId = `${baseId}-heading`;
|
|
803
865
|
const Tag = `h${headingLevel}`;
|
|
804
866
|
function toggle(id) {
|
|
@@ -809,6 +871,44 @@ function CourseSyllabus({
|
|
|
809
871
|
return next;
|
|
810
872
|
});
|
|
811
873
|
}
|
|
874
|
+
function previewHref(lesson) {
|
|
875
|
+
if (getPreviewHref) return getPreviewHref(lesson);
|
|
876
|
+
return previewHrefTemplate ? fillTemplate(previewHrefTemplate, lesson) : void 0;
|
|
877
|
+
}
|
|
878
|
+
function renderPreview(lesson) {
|
|
879
|
+
const name = `${labels.freePreview}: ${lesson.title}`;
|
|
880
|
+
const href = previewHref(lesson);
|
|
881
|
+
if (href) {
|
|
882
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("a", { href, "aria-label": name, "data-slot": "course-syllabus-preview", className: PREVIEW_CTA, children: [
|
|
883
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PlayIcon, {}),
|
|
884
|
+
labels.freePreview
|
|
885
|
+
] });
|
|
886
|
+
}
|
|
887
|
+
if (onPreview) {
|
|
888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
889
|
+
"button",
|
|
890
|
+
{
|
|
891
|
+
type: "button",
|
|
892
|
+
"aria-label": name,
|
|
893
|
+
"data-slot": "course-syllabus-preview",
|
|
894
|
+
onClick: () => onPreview(lesson),
|
|
895
|
+
className: (0, import_utils8.cn)(PREVIEW_CTA, "cursor-pointer"),
|
|
896
|
+
children: [
|
|
897
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PlayIcon, {}),
|
|
898
|
+
labels.freePreview
|
|
899
|
+
]
|
|
900
|
+
}
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
904
|
+
"span",
|
|
905
|
+
{
|
|
906
|
+
"data-slot": "course-syllabus-preview",
|
|
907
|
+
className: "rounded-full bg-muted px-2.5 py-0.5 text-xs font-medium text-muted-foreground",
|
|
908
|
+
children: labels.freePreview
|
|
909
|
+
}
|
|
910
|
+
);
|
|
911
|
+
}
|
|
812
912
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
813
913
|
"section",
|
|
814
914
|
{
|
|
@@ -816,24 +916,43 @@ function CourseSyllabus({
|
|
|
816
916
|
"aria-labelledby": headingId,
|
|
817
917
|
className: (0, import_utils8.cn)("space-y-4", className),
|
|
818
918
|
children: [
|
|
819
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
children:
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
919
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
920
|
+
"div",
|
|
921
|
+
{
|
|
922
|
+
"data-slot": "course-syllabus-header",
|
|
923
|
+
className: "flex flex-wrap items-end justify-between gap-x-4 gap-y-2",
|
|
924
|
+
children: [
|
|
925
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-1", children: [
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
927
|
+
Tag,
|
|
928
|
+
{
|
|
929
|
+
id: headingId,
|
|
930
|
+
className: slotClassName("", "text-xl font-semibold", headingClassName),
|
|
931
|
+
children: labels.heading
|
|
932
|
+
}
|
|
933
|
+
),
|
|
934
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { "data-slot": "course-syllabus-summary", className: "text-sm text-muted-foreground", children: summary.join(SEPARATOR) })
|
|
935
|
+
] }),
|
|
936
|
+
expandable.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
937
|
+
"button",
|
|
938
|
+
{
|
|
939
|
+
type: "button",
|
|
940
|
+
"data-slot": "course-syllabus-toggle-all",
|
|
941
|
+
onClick: () => setOpen(allOpen ? /* @__PURE__ */ new Set() : new Set(expandable)),
|
|
942
|
+
className: "cursor-pointer rounded-md px-2 py-1 text-sm font-semibold text-primary underline-offset-4 hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
|
|
943
|
+
children: allOpen ? labels.collapseAll : labels.expandAll
|
|
944
|
+
}
|
|
945
|
+
)
|
|
946
|
+
]
|
|
947
|
+
}
|
|
948
|
+
),
|
|
949
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ol", { className: "list-none divide-y divide-border overflow-hidden rounded-xl border border-border bg-card p-0", children: modules.map((module2, index) => {
|
|
831
950
|
const lessons = module2.lessons ?? [];
|
|
832
951
|
const number = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
833
952
|
"span",
|
|
834
953
|
{
|
|
835
954
|
"aria-hidden": "true",
|
|
836
|
-
className: "flex size-
|
|
955
|
+
className: "flex size-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-sm font-semibold text-primary tabular-nums",
|
|
837
956
|
children: index + 1
|
|
838
957
|
}
|
|
839
958
|
);
|
|
@@ -842,7 +961,7 @@ function CourseSyllabus({
|
|
|
842
961
|
"li",
|
|
843
962
|
{
|
|
844
963
|
"data-slot": "course-syllabus-module",
|
|
845
|
-
className: "flex items-center gap-
|
|
964
|
+
className: "flex items-center gap-4 px-4 py-4 sm:px-5",
|
|
846
965
|
children: [
|
|
847
966
|
number,
|
|
848
967
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold leading-snug", children: module2.title })
|
|
@@ -853,69 +972,85 @@ function CourseSyllabus({
|
|
|
853
972
|
}
|
|
854
973
|
const isOpen = open.has(module2.id);
|
|
855
974
|
const panelId = `${baseId}-module-${index}`;
|
|
856
|
-
const seconds =
|
|
975
|
+
const seconds = totalSeconds(lessons);
|
|
857
976
|
const meta = [count(lessons.length, labels.lessonSingular, labels.lessonPlural)];
|
|
858
|
-
if (seconds !== null) meta.push(
|
|
859
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
"aria-controls": panelId,
|
|
871
|
-
onClick: () => toggle(module2.id),
|
|
872
|
-
className: "flex w-full cursor-pointer items-center gap-3.5 rounded-lg px-4 py-3.5 text-left focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
|
|
873
|
-
children: [
|
|
874
|
-
number,
|
|
875
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
876
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold leading-snug", children: module2.title }),
|
|
877
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm text-muted-foreground", children: meta.join(SEPARATOR) })
|
|
878
|
-
] }),
|
|
879
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
880
|
-
"span",
|
|
881
|
-
{
|
|
882
|
-
"aria-hidden": "true",
|
|
883
|
-
className: (0, import_utils8.cn)(
|
|
884
|
-
"shrink-0 text-muted-foreground transition-transform motion-reduce:transition-none",
|
|
885
|
-
isOpen && "rotate-180"
|
|
886
|
-
),
|
|
887
|
-
children: "\u25BE"
|
|
888
|
-
}
|
|
889
|
-
)
|
|
890
|
-
]
|
|
891
|
-
}
|
|
977
|
+
if (seconds !== null) meta.push(formatTotal(seconds, labels));
|
|
978
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { "data-slot": "course-syllabus-module", children: [
|
|
979
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
980
|
+
"button",
|
|
981
|
+
{
|
|
982
|
+
type: "button",
|
|
983
|
+
"aria-expanded": isOpen,
|
|
984
|
+
"aria-controls": panelId,
|
|
985
|
+
onClick: () => toggle(module2.id),
|
|
986
|
+
className: (0, import_utils8.cn)(
|
|
987
|
+
"flex w-full cursor-pointer items-center gap-4 px-4 py-4 text-left transition-colors hover:bg-muted/60 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none sm:px-5",
|
|
988
|
+
isOpen && "bg-muted/40"
|
|
892
989
|
),
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
{
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
990
|
+
children: [
|
|
991
|
+
number,
|
|
992
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
993
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold leading-snug", children: module2.title }),
|
|
994
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm text-muted-foreground", children: meta.join(SEPARATOR) })
|
|
995
|
+
] }),
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
997
|
+
"svg",
|
|
998
|
+
{
|
|
999
|
+
...ICON_PROPS,
|
|
1000
|
+
"data-slot": "course-syllabus-chevron",
|
|
1001
|
+
className: (0, import_utils8.cn)(
|
|
1002
|
+
"size-5 shrink-0 text-muted-foreground transition-transform duration-200 motion-reduce:transition-none",
|
|
1003
|
+
isOpen && "rotate-180"
|
|
1004
|
+
),
|
|
1005
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "m6 9 6 6 6-6" })
|
|
1006
|
+
}
|
|
1007
|
+
)
|
|
1008
|
+
]
|
|
1009
|
+
}
|
|
1010
|
+
),
|
|
1011
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1012
|
+
"ol",
|
|
1013
|
+
{
|
|
1014
|
+
id: panelId,
|
|
1015
|
+
hidden: !isOpen,
|
|
1016
|
+
"data-slot": "course-syllabus-lessons",
|
|
1017
|
+
className: "list-none border-t border-border p-0 py-1",
|
|
1018
|
+
children: lessons.map((lesson) => {
|
|
1019
|
+
const type = lesson.hasVideo ? "video" : "text";
|
|
1020
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1021
|
+
"li",
|
|
1022
|
+
{
|
|
1023
|
+
"data-slot": "course-syllabus-lesson",
|
|
1024
|
+
className: "flex flex-wrap items-center gap-x-3 gap-y-1.5 px-4 py-2.5 text-sm sm:pl-[4.25rem] sm:pr-5",
|
|
1025
|
+
children: [
|
|
1026
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(LessonIcon, { type }),
|
|
1027
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "sr-only", children: type === "video" ? labels.videoLesson : labels.textLesson }),
|
|
1028
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1029
|
+
"span",
|
|
1030
|
+
{
|
|
1031
|
+
"data-slot": "course-syllabus-lesson-title",
|
|
1032
|
+
className: "min-w-0 flex-1 leading-snug",
|
|
1033
|
+
children: lesson.title
|
|
1034
|
+
}
|
|
1035
|
+
),
|
|
1036
|
+
lesson.isFreePreview && renderPreview(lesson),
|
|
1037
|
+
hasDuration(lesson) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1038
|
+
"time",
|
|
1039
|
+
{
|
|
1040
|
+
"data-slot": "course-syllabus-lesson-duration",
|
|
1041
|
+
dateTime: isoDuration(lesson.durationSeconds),
|
|
1042
|
+
className: "ml-auto shrink-0 text-muted-foreground tabular-nums",
|
|
1043
|
+
children: formatClock(lesson.durationSeconds)
|
|
1044
|
+
}
|
|
1045
|
+
)
|
|
1046
|
+
]
|
|
1047
|
+
},
|
|
1048
|
+
lesson.id
|
|
1049
|
+
);
|
|
1050
|
+
})
|
|
1051
|
+
}
|
|
1052
|
+
)
|
|
1053
|
+
] }, module2.id);
|
|
919
1054
|
}) })
|
|
920
1055
|
]
|
|
921
1056
|
}
|