wagtail-cjkcms 24.11.1__py2.py3-none-any.whl → 24.12.2__py2.py3-none-any.whl

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 (31) hide show
  1. cjkcms/.DS_Store +0 -0
  2. cjkcms/__init__.py +1 -1
  3. cjkcms/blocks/__init__.py +2 -0
  4. cjkcms/blocks/content/countdown.py +116 -0
  5. cjkcms/static/vendor/simplycountdown/css/circle.css +73 -0
  6. cjkcms/static/vendor/simplycountdown/css/cyber.css +155 -0
  7. cjkcms/static/vendor/simplycountdown/css/dark.css +85 -0
  8. cjkcms/static/vendor/simplycountdown/css/light.css +85 -0
  9. cjkcms/static/vendor/simplycountdown/css/losange.css +83 -0
  10. cjkcms/static/vendor/simplycountdown/js/simplyCountdown.umd.js +2 -0
  11. cjkcms/static/vendor/simplycountdown/js/simplyCountdown.umd.js.map +1 -0
  12. cjkcms/templates/.DS_Store +0 -0
  13. cjkcms/templates/cjkcms/.DS_Store +0 -0
  14. cjkcms/templates/cjkcms/blocks/button_block.html +1 -1
  15. cjkcms/templates/cjkcms/blocks/countdown.html +24 -0
  16. cjkcms/templatetags/cjkcms_tags.py +5 -0
  17. cjkcms/tests/test_countdown_block.py +100 -0
  18. {wagtail_cjkcms-24.11.1.dist-info → wagtail_cjkcms-24.12.2.dist-info}/METADATA +1 -1
  19. {wagtail_cjkcms-24.11.1.dist-info → wagtail_cjkcms-24.12.2.dist-info}/RECORD +23 -18
  20. cjkcms/media/images/test.original.png +0 -0
  21. cjkcms/media/original_images/test.png +0 -0
  22. cjkcms/tests/media/images/test_oKdmwQn.original.png +0 -0
  23. cjkcms/tests/media/images/test_otfQve2.original.png +0 -0
  24. cjkcms/tests/media/images/test_qFhTLcX.original.png +0 -0
  25. cjkcms/tests/media/original_images/test_oKdmwQn.png +0 -0
  26. cjkcms/tests/media/original_images/test_otfQve2.png +0 -0
  27. cjkcms/tests/media/original_images/test_qFhTLcX.png +0 -0
  28. {wagtail_cjkcms-24.11.1.dist-info → wagtail_cjkcms-24.12.2.dist-info}/LICENSE +0 -0
  29. {wagtail_cjkcms-24.11.1.dist-info → wagtail_cjkcms-24.12.2.dist-info}/WHEEL +0 -0
  30. {wagtail_cjkcms-24.11.1.dist-info → wagtail_cjkcms-24.12.2.dist-info}/entry_points.txt +0 -0
  31. {wagtail_cjkcms-24.11.1.dist-info → wagtail_cjkcms-24.12.2.dist-info}/top_level.txt +0 -0
cjkcms/.DS_Store ADDED
Binary file
cjkcms/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- VERSION = (24, 11, 1, "")
1
+ VERSION = (24, 12, 2, "")
2
2
 
3
3
  __version_info__ = VERSION
4
4
  __version__ = ".".join(map(str, VERSION[:3])) + (f"-{VERSION[3]}" if VERSION[3] else "")
cjkcms/blocks/__init__.py CHANGED
@@ -34,6 +34,7 @@ from .content_blocks import ( # noqa
34
34
  HighlightBlock,
35
35
  )
36
36
  from .content.events import PublicEventBlock, EventCalendarBlock
37
+ from .content.countdown import CountdownBlock
37
38
  from .layout_blocks import CardGridBlock, GridBlock, HeroBlock
38
39
  from cjkcms.settings import cms_settings
39
40
 
@@ -77,6 +78,7 @@ CONTENT_STREAMBLOCKS = HTML_STREAMBLOCKS + [
77
78
  ("reusable_content", ReusableContentBlock()),
78
79
  ("event_calendar", EventCalendarBlock()),
79
80
  ("highlight", HighlightBlock()),
81
+ ("countdown", CountdownBlock()),
80
82
  ]
81
83
 
82
84
  NAVIGATION_STREAMBLOCKS = [
@@ -0,0 +1,116 @@
1
+ from cjkcms.blocks.base_blocks import BaseBlock
2
+ from wagtail import blocks
3
+ from django.utils.translation import gettext_lazy as _
4
+ from datetime import datetime, timedelta, timezone
5
+ import re
6
+
7
+
8
+ def convert_to_utc(naive_dt, utc_offset_str):
9
+ # Parse the UTC offset string (e.g., "UTC+05:30" or "UTC-02:00")
10
+ match = re.match(r"UTC([+-])(\d{2}):(\d{2})", utc_offset_str)
11
+ if not match:
12
+ raise ValueError("Invalid UTC offset format. Use 'UTC±HH:MM'.")
13
+
14
+ sign = match.group(1)
15
+ hours = int(match.group(2))
16
+ minutes = int(match.group(3))
17
+
18
+ # Calculate the total offset in minutes
19
+ total_offset = timedelta(hours=hours, minutes=minutes)
20
+ if sign == "-":
21
+ total_offset = -total_offset
22
+
23
+ # Create a timezone with the given offset
24
+ tz = timezone(total_offset)
25
+
26
+ # Attach the offset to the naive datetime, making it timezone-aware
27
+ aware_local_dt = naive_dt.replace(tzinfo=tz)
28
+
29
+ # Convert the timezone-aware datetime to UTC
30
+ utc_dt = aware_local_dt.astimezone(timezone.utc)
31
+
32
+ return utc_dt
33
+
34
+
35
+ class CountdownBlock(BaseBlock):
36
+ """
37
+ Display a countdown to a specific date
38
+ """
39
+
40
+ title = blocks.CharBlock(
41
+ required=False,
42
+ max_length=255,
43
+ label=_("Title"),
44
+ )
45
+
46
+ start_date = blocks.DateTimeBlock(
47
+ required=True,
48
+ label=_("Start date and time"),
49
+ help_text=_("Format: YYYY-MM-DD HH:MM"),
50
+ )
51
+
52
+ timezone = blocks.CharBlock(
53
+ required=True,
54
+ default="UTC",
55
+ max_length=255,
56
+ label=_("Timezone"),
57
+ help_text=_("Timezone relative to UTC, e.g. UTC+01:00"),
58
+ )
59
+
60
+ url = blocks.URLBlock(
61
+ max_length=255,
62
+ label=_("Link"),
63
+ required=False,
64
+ help_text=_("Optional link"),
65
+ )
66
+
67
+ # hide_after_end_date = blocks.BooleanBlock(
68
+ # required=False,
69
+ # default=False,
70
+ # label=_("Hide after end date"),
71
+ # help_text=_("Hide this after end date, or show zeros if false"),
72
+ # )
73
+
74
+ theme = blocks.ChoiceBlock(
75
+ choices=[
76
+ ("light", _("Light")),
77
+ ("dark", _("Dark")),
78
+ ("cyber", _("Cyberpunk")),
79
+ ("losange", _("Losange")),
80
+ ("circle", _("Circle")),
81
+ # ("flipbook", _("Flipbook")),
82
+ ],
83
+ default="light",
84
+ label=_("Theme"),
85
+ )
86
+
87
+ def get_context(self, value, parent_context=None):
88
+ context = super().get_context(value, parent_context=parent_context)
89
+ sd = value.get("start_date")
90
+
91
+ naive_datetime = datetime(
92
+ sd.year, sd.month, sd.day, sd.hour, sd.minute
93
+ ) # Naive datetime
94
+
95
+ tz = value.get("timezone")
96
+ if tz == "UTC" or tz == "":
97
+ tz = "UTC+00:00"
98
+
99
+ utc_offset_string = tz # String containing UTC offset
100
+ utc = convert_to_utc(naive_datetime, utc_offset_string)
101
+
102
+ # print(naive_datetime, utc, utc_offset_string)
103
+ context["year"] = utc.year
104
+ context["month"] = utc.month
105
+ context["day"] = utc.day
106
+ context["hour"] = utc.hour
107
+ context["minute"] = utc.minute
108
+ context["second"] = 0
109
+ return context
110
+
111
+ class Meta:
112
+ template = "cjkcms/blocks/countdown.html"
113
+ icon = "history"
114
+ label = "Countdown"
115
+ ordering = ["start_date"]
116
+ label_format = _("Countdown to {start_date}")
@@ -0,0 +1,73 @@
1
+ .simply-countdown-circle {
2
+ --sc-circle-primary: #6366f1;
3
+ --sc-circle-secondary: #818cf8;
4
+ --sc-circle-bg: #1e1b4b;
5
+ --sc-circle-text: #fff;
6
+
7
+ display: flex;
8
+ flex-wrap: wrap;
9
+ justify-content: center;
10
+ gap: 1.5rem;
11
+ font-family: "Inter", sans-serif;
12
+ }
13
+
14
+ .simply-countdown-circle > .simply-section {
15
+ position: relative;
16
+ width: 100px;
17
+ height: 100px;
18
+ padding: 1rem;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ flex-direction: column;
23
+ border-radius: 50%;
24
+ background: linear-gradient(45deg, var(--sc-circle-primary), var(--sc-circle-secondary));
25
+ box-shadow: 0 0 25px -5px var(--sc-circle-primary);
26
+ animation: pulse-circle 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
27
+ }
28
+
29
+ .simply-countdown-circle > .simply-section::before {
30
+ content: "";
31
+ position: absolute;
32
+ inset: 6px;
33
+ border-radius: 50%;
34
+ background: var(--sc-circle-bg);
35
+ z-index: 0;
36
+ }
37
+
38
+ .simply-countdown-circle > .simply-section > div {
39
+ position: relative;
40
+ z-index: 1;
41
+ color: var(--sc-circle-text);
42
+ text-align: center;
43
+ }
44
+
45
+ .simply-countdown-circle .simply-amount {
46
+ display: block;
47
+ font-size: 1.75rem;
48
+ font-weight: 700;
49
+ line-height: 1;
50
+ background: linear-gradient(to right, var(--sc-circle-primary), var(--sc-circle-secondary));
51
+ -webkit-background-clip: text;
52
+ background-clip: text;
53
+ -webkit-text-fill-color: transparent;
54
+ }
55
+
56
+ .simply-countdown-circle .simply-word {
57
+ font-size: 0.7rem;
58
+ text-transform: uppercase;
59
+ letter-spacing: 0.05em;
60
+ opacity: 0.8;
61
+ }
62
+
63
+ @keyframes pulse-circle {
64
+ 0%,
65
+ 100% {
66
+ transform: scale(1);
67
+ opacity: 1;
68
+ }
69
+ 50% {
70
+ transform: scale(0.98);
71
+ opacity: 0.9;
72
+ }
73
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Project : simply-countdown
3
+ * File : simplyCountdown.theme.cyberpunk
4
+ * Author : Vincent Loy <vincent.loy1@gmail.com>
5
+ * Theme : Modern Cyberpunk
6
+ */
7
+
8
+ .simply-countdown-cyber {
9
+ overflow: visible;
10
+ display: flex;
11
+ flex-wrap: wrap;
12
+ justify-content: center;
13
+ gap: 1.75rem;
14
+ font-family: "Inter", system-ui, -apple-system, sans-serif;
15
+ perspective: 1000px;
16
+ }
17
+
18
+ .simply-countdown-cyber > .simply-section {
19
+ width: 70px;
20
+ height: 70px;
21
+ padding: 1.5rem;
22
+ position: relative;
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ background: linear-gradient(135deg, rgba(23, 25, 35, 0.9), rgba(15, 17, 25, 0.95));
27
+ border-radius: 0.5rem;
28
+ transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
29
+ backdrop-filter: blur(12px);
30
+ transform-style: preserve-3d;
31
+ }
32
+
33
+ .simply-countdown-cyber > .simply-section::before {
34
+ content: "";
35
+ position: absolute;
36
+ inset: -1px;
37
+ background: linear-gradient(135deg, rgba(120, 240, 255, 0.2), rgba(255, 90, 220, 0.2));
38
+ border-radius: 0.5rem;
39
+ z-index: -1;
40
+ opacity: 0;
41
+ transition: opacity 0.3s ease;
42
+ }
43
+
44
+ .simply-countdown-cyber > .simply-section::after {
45
+ content: "";
46
+ position: absolute;
47
+ inset: -2px;
48
+ background: linear-gradient(135deg, #78f0ff, #ff5adc);
49
+ border-radius: 0.5rem;
50
+ z-index: -2;
51
+ opacity: 0.15;
52
+ filter: blur(4px);
53
+ animation: pulse 4s ease-in-out infinite;
54
+ }
55
+
56
+ .simply-countdown-cyber > .simply-section .glass-overlay {
57
+ position: absolute;
58
+ inset: 0;
59
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05));
60
+ border-radius: 0.5rem;
61
+ }
62
+
63
+ .simply-countdown-cyber > .simply-section:hover {
64
+ transform: translateY(-4px) translateZ(10px) rotateX(5deg);
65
+ box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.5), 0 0 20px rgba(120, 240, 255, 0.2), 0 0 0 1px rgba(120, 240, 255, 0.1);
66
+ }
67
+
68
+ .simply-countdown-cyber > .simply-section:hover::before {
69
+ opacity: 1;
70
+ }
71
+
72
+ .simply-countdown-cyber > .simply-section > div {
73
+ display: flex;
74
+ flex-direction: column;
75
+ gap: 0.4rem;
76
+ align-items: center;
77
+ transform-style: preserve-3d;
78
+ }
79
+
80
+ .simply-countdown-cyber > .simply-section .simply-amount {
81
+ font-size: 1.75rem;
82
+ font-weight: 700;
83
+ background: linear-gradient(to bottom right, #78f0ff, #ff5adc);
84
+ -webkit-background-clip: text;
85
+ background-clip: text;
86
+ color: transparent;
87
+ text-shadow: 0 0 20px rgba(120, 240, 255, 0.3), 0 0 40px rgba(120, 240, 255, 0.2);
88
+ letter-spacing: -0.02em;
89
+ transform: translateZ(10px);
90
+ }
91
+
92
+ .simply-countdown-cyber > .simply-section .simply-word {
93
+ font-size: 0.6rem;
94
+ font-weight: 500;
95
+ text-transform: uppercase;
96
+ letter-spacing: 0.2em;
97
+ color: rgba(255, 255, 255, 0.7);
98
+ transform: translateZ(5px);
99
+ position: relative;
100
+ }
101
+
102
+ .simply-countdown-cyber > .simply-section .simply-word::after {
103
+ content: "";
104
+ position: absolute;
105
+ left: -10%;
106
+ bottom: -4px;
107
+ width: 120%;
108
+ height: 1px;
109
+ background: linear-gradient(to right, rgba(120, 240, 255, 0), rgba(120, 240, 255, 0.5), rgba(255, 90, 220, 0.5), rgba(255, 90, 220, 0));
110
+ }
111
+
112
+ @media (min-width: 640px) {
113
+ .simply-countdown-cyber > .simply-section {
114
+ width: 80px;
115
+ height: 80px;
116
+ padding: 1.75rem;
117
+ }
118
+
119
+ .simply-countdown-cyber > .simply-section .simply-amount {
120
+ font-size: 2rem;
121
+ }
122
+
123
+ .simply-countdown-cyber > .simply-section .simply-word {
124
+ font-size: 0.75rem;
125
+ }
126
+ }
127
+
128
+ @media (min-width: 1024px) {
129
+ .simply-countdown-cyber > .simply-section {
130
+ width: 100px;
131
+ height: 100px;
132
+ padding: 2rem;
133
+ }
134
+
135
+ .simply-countdown-cyber > .simply-section .simply-amount {
136
+ font-size: 2.5rem;
137
+ }
138
+
139
+ .simply-countdown-cyber > .simply-section .simply-word {
140
+ font-size: 0.8rem;
141
+ }
142
+ }
143
+
144
+ /* Add subtle animation for extra futuristic feel */
145
+ @keyframes pulse {
146
+ 0%,
147
+ 100% {
148
+ opacity: 0.15;
149
+ transform: scale(1);
150
+ }
151
+ 50% {
152
+ opacity: 0.25;
153
+ transform: scale(1.05);
154
+ }
155
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Project : simply-countdown
3
+ * File : simplyCountdown.theme.dark
4
+ * Author : Vincent Loy <vincent.loy1@gmail.com>
5
+ * Theme : Dark Modern
6
+ */
7
+
8
+ .simply-countdown-dark {
9
+ overflow: hidden;
10
+ display: flex;
11
+ flex-wrap: wrap;
12
+ justify-content: center;
13
+ gap: 1.25rem;
14
+ font-family: "Inter", system-ui, -apple-system, sans-serif;
15
+ }
16
+
17
+ .simply-countdown-dark > .simply-section {
18
+ width: 65px;
19
+ height: 65px;
20
+ padding: 1.5rem;
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ background: rgba(15, 23, 42, 0.75);
25
+ border: 1px solid rgba(51, 65, 85, 0.6);
26
+ border-radius: 1rem;
27
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2), 0 2px 4px -1px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(255, 255, 255, 0.05);
28
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
29
+ backdrop-filter: blur(10px);
30
+ }
31
+
32
+ .simply-countdown-dark > .simply-section > div {
33
+ display: flex;
34
+ flex-direction: column;
35
+ line-height: 1;
36
+ align-items: center;
37
+ }
38
+
39
+ .simply-countdown-dark > .simply-section .simply-amount {
40
+ font-size: 1.5rem;
41
+ font-weight: 700;
42
+ color: #f1f5f9;
43
+ line-height: 1.2;
44
+ letter-spacing: -0.025em;
45
+ }
46
+
47
+ .simply-countdown-dark > .simply-section .simply-word {
48
+ font-size: 0.6rem;
49
+ font-weight: 500;
50
+ color: #94a3b8;
51
+ text-transform: uppercase;
52
+ letter-spacing: 0.1em;
53
+ }
54
+
55
+ @media (min-width: 640px) {
56
+ .simply-countdown-dark > .simply-section {
57
+ width: 75px;
58
+ height: 75px;
59
+ padding: 1.75rem;
60
+ }
61
+
62
+ .simply-countdown-dark > .simply-section .simply-amount {
63
+ font-size: 1.75rem;
64
+ }
65
+
66
+ .simply-countdown-dark > .simply-section .simply-word {
67
+ font-size: 0.75rem;
68
+ }
69
+ }
70
+
71
+ @media (min-width: 1024px) {
72
+ .simply-countdown-dark > .simply-section {
73
+ width: 90px;
74
+ height: 90px;
75
+ padding: 2rem;
76
+ }
77
+
78
+ .simply-countdown-dark > .simply-section .simply-amount {
79
+ font-size: 2rem;
80
+ }
81
+
82
+ .simply-countdown-dark > .simply-section .simply-word {
83
+ font-size: 0.8rem;
84
+ }
85
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Project : simply-countdown
3
+ * File : simplyCountdown.theme.default
4
+ * Author : Vincent Loy <vincent.loy1@gmail.com>
5
+ * Theme : Light Modern
6
+ */
7
+
8
+ .simply-countdown-light {
9
+ overflow: hidden;
10
+ display: flex;
11
+ flex-wrap: wrap;
12
+ justify-content: center;
13
+ gap: 1.25rem;
14
+ font-family: "Inter", system-ui, -apple-system, sans-serif;
15
+ }
16
+
17
+ .simply-countdown-light > .simply-section {
18
+ width: 65px;
19
+ height: 65px;
20
+ padding: 1.5rem;
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ background: rgba(255, 255, 255, 0.9);
25
+ border: 1px solid rgba(226, 232, 240, 0.8);
26
+ border-radius: 1rem;
27
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03), 0 0 0 1px rgba(0, 0, 0, 0.02);
28
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
29
+ backdrop-filter: blur(10px);
30
+ }
31
+
32
+ .simply-countdown-light > .simply-section > div {
33
+ display: flex;
34
+ flex-direction: column;
35
+ line-height: 1;
36
+ align-items: center;
37
+ }
38
+
39
+ .simply-countdown-light > .simply-section .simply-amount {
40
+ font-size: 1.5rem;
41
+ font-weight: 700;
42
+ color: #1e293b;
43
+ line-height: 1.2;
44
+ letter-spacing: -0.025em;
45
+ }
46
+
47
+ .simply-countdown-light > .simply-section .simply-word {
48
+ font-size: 0.6rem;
49
+ font-weight: 500;
50
+ color: #64748b;
51
+ text-transform: uppercase;
52
+ letter-spacing: 0.1em;
53
+ }
54
+
55
+ @media (min-width: 640px) {
56
+ .simply-countdown-light > .simply-section {
57
+ width: 75px;
58
+ height: 75px;
59
+ padding: 1.75rem;
60
+ }
61
+
62
+ .simply-countdown-light > .simply-section .simply-amount {
63
+ font-size: 1.75rem;
64
+ }
65
+
66
+ .simply-countdown-light > .simply-section .simply-word {
67
+ font-size: 0.75rem;
68
+ }
69
+ }
70
+
71
+ @media (min-width: 1024px) {
72
+ .simply-countdown-light > .simply-section {
73
+ width: 90px;
74
+ height: 90px;
75
+ padding: 2rem;
76
+ }
77
+
78
+ .simply-countdown-light > .simply-section .simply-amount {
79
+ font-size: 2rem;
80
+ }
81
+
82
+ .simply-countdown-light > .simply-section .simply-word {
83
+ font-size: 0.8rem;
84
+ }
85
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Project : simply-countdown
3
+ * File : simplyCountdown.theme.losange
4
+ * Author : Vincent Loy <vincent.loy1@gmail.com>
5
+ */
6
+
7
+ .simply-countdown-losange {
8
+ overflow: visible;
9
+ display: flex;
10
+ flex-wrap: wrap;
11
+ justify-content: center;
12
+ gap: 3rem;
13
+ font-family: "Inter", sans-serif;
14
+ }
15
+
16
+ .simply-countdown-losange > .simply-section {
17
+ width: 70px;
18
+ height: 70px;
19
+ display: flex;
20
+ justify-content: center;
21
+ align-items: center;
22
+ transform: rotate(-45deg);
23
+ background: linear-gradient(135deg, #4f46e5, #7c3aed);
24
+ border-radius: 0.5rem;
25
+ transition: all 0.2s ease-in-out;
26
+ }
27
+
28
+ .simply-countdown-losange > .simply-section > div {
29
+ transform: rotate(45deg);
30
+ display: flex;
31
+ flex-direction: column;
32
+ line-height: 1.2;
33
+ }
34
+
35
+ .simply-countdown-losange > .simply-section .simply-amount,
36
+ .simply-countdown-losange > .simply-section .simply-word {
37
+ display: block;
38
+ text-align: center;
39
+ }
40
+
41
+ .simply-countdown-losange > .simply-section .simply-amount {
42
+ font-size: 1.25rem;
43
+ font-weight: 700;
44
+ color: #fff;
45
+ }
46
+
47
+ .simply-countdown-losange > .simply-section .simply-word {
48
+ font-size: 0.65rem;
49
+ font-weight: 500;
50
+ color: rgba(255, 255, 255, 0.9);
51
+ text-transform: uppercase;
52
+ letter-spacing: 0.05em;
53
+ }
54
+
55
+ @media (min-width: 640px) {
56
+ .simply-countdown-losange > .simply-section {
57
+ width: 80px;
58
+ height: 80px;
59
+ }
60
+
61
+ .simply-countdown-losange > .simply-section .simply-amount {
62
+ font-size: 1.5rem;
63
+ }
64
+
65
+ .simply-countdown-losange > .simply-section .simply-word {
66
+ font-size: 0.7rem;
67
+ }
68
+ }
69
+
70
+ @media (min-width: 1024px) {
71
+ .simply-countdown-losange > .simply-section {
72
+ width: 90px;
73
+ height: 90px;
74
+ }
75
+
76
+ .simply-countdown-losange > .simply-section .simply-amount {
77
+ font-size: 1.75rem;
78
+ }
79
+
80
+ .simply-countdown-losange > .simply-section .simply-word {
81
+ font-size: 0.75rem;
82
+ }
83
+ }
@@ -0,0 +1,2 @@
1
+ !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define("simplyCountdown",n):(e="undefined"!=typeof globalThis?globalThis:e||self).simplyCountdown=n()}(this,(function(){"use strict";const e=(e,n,t,o,s,a)=>{const l=document.createElement("div");l.className=`${e} ${a.sectionClass}`;const r=document.createElement("div"),d=document.createElement("span"),i=document.createElement("span");return d.className=`${n} ${a.amountClass}`,i.className=`${t} ${a.wordClass}`,d.textContent=String(o),i.textContent=s,r.appendChild(d),r.appendChild(i),l.appendChild(r),l},n={year:2024,month:12,day:25,hours:0,minutes:0,seconds:0,words:{days:{lambda:(e,n)=>n>1?e+"s":e,root:"day"},hours:{lambda:(e,n)=>n>1?e+"s":e,root:"hour"},minutes:{lambda:(e,n)=>n>1?e+"s":e,root:"minute"},seconds:{lambda:(e,n)=>n>1?e+"s":e,root:"second"}},plural:!0,inline:!1,inlineSeparator:", ",enableUtc:!1,onEnd:()=>{},refresh:1e3,inlineClass:"simply-countdown-inline",sectionClass:"simply-section",amountClass:"simply-amount",wordClass:"simply-word",zeroPad:!1,countUp:!1,removeZeroUnits:!1,onStop:()=>{},onResume:()=>{},onUpdate:()=>{}};function t(e,n,t){return!t.removeZeroUnits||(0!==e.value||n.some((e=>0!==e.value)))}function o(e,n,o){const s=e.filter(((o,s)=>t(o,e.slice(0,s),n))).map((e=>function(e,n){return`${n.zeroPad?String(e.value).padStart(2,"0"):e.value} ${n.words[e.word].lambda(n.words[e.word].root,e.value)}`}(e,n))).join(n.inlineSeparator);o.innerHTML=s}function s(e,n,o){e.forEach(((s,a)=>{"seconds"===s.word||t(s,e.slice(0,a),n)?(((e,n,t)=>{const o=e.querySelector(".simply-amount"),s=e.querySelector(".simply-word");o&&(o.textContent=String(n)),s&&(s.textContent=t)})(o[s.word],n.zeroPad?String(s.value).padStart(2,"0"):s.value,n.words[s.word].lambda(n.words[s.word].root,s.value)),o[s.word].style.display=""):o[s.word].style.display="none"}))}const a=(n,t)=>{let a={isPaused:!1,interval:null,targetDate:new Date};const l=e=>e.enableUtc?new Date(Date.UTC(e.year,e.month-1,e.day,e.hours,e.minutes,e.seconds)):new Date(e.year,e.month-1,e.day,e.hours,e.minutes,e.seconds);a.targetDate=l(t);let r=null;t.inline&&(r=document.createElement("span"),r.className=t.inlineClass,n.appendChild(r));const d=t.inline?null:((n,t)=>{const o="simply-amount",s="simply-word",a=e("simply-section simply-days-section",o,s,0,"day",t),l=e("simply-section simply-hours-section",o,s,0,"hour",t),r=e("simply-section simply-minutes-section",o,s,0,"minute",t),d=e("simply-section simply-seconds-section",o,s,0,"second",t);return n.appendChild(a),n.appendChild(l),n.appendChild(r),n.appendChild(d),{days:a,hours:l,minutes:r,seconds:d}})(n,{sectionClass:t.sectionClass,amountClass:t.amountClass,wordClass:t.wordClass}),i=()=>{const e=t.enableUtc?new Date(Date.UTC((new Date).getUTCFullYear(),(new Date).getUTCMonth(),(new Date).getUTCDate(),(new Date).getUTCHours(),(new Date).getUTCMinutes(),(new Date).getUTCSeconds())):new Date;let n=t.countUp?e.getTime()-a.targetDate.getTime():a.targetDate.getTime()-e.getTime();n<=0&&!t.countUp&&(n=0,null!==a.interval&&clearInterval(a.interval),t.onEnd&&t.onEnd());const l=Math.floor(n/864e5);n-=1e3*l*60*60*24;const i=Math.floor(n/36e5);n-=1e3*i*60*60;const u=Math.floor(n/6e4);n-=1e3*u*60;const c=Math.floor(n/1e3);if(t.inline&&r){o([{value:l,word:"days"},{value:i,word:"hours"},{value:u,word:"minutes"},{value:c,word:"seconds"}],t,r)}else if(d){s([{value:l,word:"days"},{value:i,word:"hours"},{value:u,word:"minutes"},{value:c,word:"seconds"}],t,d)}},u=()=>{a.interval=setInterval(i,t.refresh),i()};u();const c=new MutationObserver((e=>{e.forEach((e=>{e.removedNodes.forEach((e=>{e===n&&(null!==a.interval&&clearInterval(a.interval),c.disconnect())}))}))}));return n.parentNode&&c.observe(n.parentNode,{childList:!0}),{stopCountdown:()=>{var e;null!==a.interval&&(clearInterval(a.interval),a.interval=null),a.isPaused=!0,null==(e=t.onStop)||e.call(t)},resumeCountdown:()=>{var e;a.isPaused&&(u(),a.isPaused=!1,null==(e=t.onResume)||e.call(t))},updateCountdown:e=>{var n;Object.assign(t,e),void 0===e.year&&void 0===e.month&&void 0===e.day&&void 0===e.hours&&void 0===e.minutes&&void 0===e.seconds||(a.targetDate=l(t)),null==(n=t.onUpdate)||n.call(t,e),a.isPaused||(a.interval&&clearInterval(a.interval),u())},getState:()=>({...a})}},l=e=>{const n=e;return n.stopCountdown=()=>e.forEach((e=>e.stopCountdown())),n.resumeCountdown=()=>e.forEach((e=>e.resumeCountdown())),n.updateCountdown=n=>e.forEach((e=>e.updateCountdown(n))),n.getState=()=>e.map((e=>e.getState())),n},r=(e,t=n)=>{const o={...n,...t};if("string"==typeof e){const n=document.querySelectorAll(e),t=Array.from(n).map((e=>a(e,o)));return 1===t.length?t[0]:l(t)}if((e=>e instanceof NodeList)(e)){const n=Array.from(e).map((e=>a(e,o)));return 1===n.length?n[0]:l(n)}return a(e,o)};return"function"==typeof define&&define.amd?define((function(){return r})):"object"==typeof module&&module.exports?module.exports=r:window.simplyCountdown=r,r}));
2
+ //# sourceMappingURL=simplyCountdown.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simplyCountdown.umd.js","sources":["../src/core/dom.ts","../src/core/simplyCountdown.ts","../src/core/simplyCountdown.umd.ts"],"sourcesContent":["/**\n * Creates a countdown section element\n */\nexport const createCountdownSection = (\n sectionClass: string,\n amountClass: string,\n wordClass: string,\n amount: number,\n word: string,\n params: {\n sectionClass: string;\n amountClass: string;\n wordClass: string;\n }\n): HTMLElement => {\n const section = document.createElement(\"div\");\n section.className = `${sectionClass} ${params.sectionClass}`;\n\n const wrap = document.createElement(\"div\");\n const amount_elem = document.createElement(\"span\");\n const word_elem = document.createElement(\"span\");\n\n amount_elem.className = `${amountClass} ${params.amountClass}`;\n word_elem.className = `${wordClass} ${params.wordClass}`;\n\n amount_elem.textContent = String(amount);\n word_elem.textContent = word;\n\n wrap.appendChild(amount_elem);\n wrap.appendChild(word_elem);\n section.appendChild(wrap);\n\n return section;\n};\n\n/**\n * Retrieves a countdown section element from a container\n */\nexport const getCountdownSection = (sectionClass: string, container: HTMLElement): HTMLElement | null => {\n return container.querySelector(`.simply-section.${sectionClass}`);\n};\n\n/**\n * Updates a countdown section element\n */\nexport const updateCountdownSection = (section: HTMLElement, amount: number | string, word: string): void => {\n const amountElement = section.querySelector(\".simply-amount\");\n const wordElement = section.querySelector(\".simply-word\");\n\n if (amountElement) {\n amountElement.textContent = String(amount);\n }\n if (wordElement) {\n wordElement.textContent = word;\n }\n};\n\n/**\n * Creates all countdown elements\n */\nexport const createCountdown = (\n container: HTMLElement,\n params: {\n sectionClass: string;\n amountClass: string;\n wordClass: string;\n }\n): {\n days: HTMLElement;\n hours: HTMLElement;\n minutes: HTMLElement;\n seconds: HTMLElement;\n} => {\n const amountCls = \"simply-amount\";\n const wordCls = \"simply-word\";\n\n const days = createCountdownSection(\"simply-section simply-days-section\", amountCls, wordCls, 0, \"day\", params);\n const hours = createCountdownSection(\"simply-section simply-hours-section\", amountCls, wordCls, 0, \"hour\", params);\n const minutes = createCountdownSection(\"simply-section simply-minutes-section\", amountCls, wordCls, 0, \"minute\", params);\n const seconds = createCountdownSection(\"simply-section simply-seconds-section\", amountCls, wordCls, 0, \"second\", params);\n\n container.appendChild(days);\n container.appendChild(hours);\n container.appendChild(minutes);\n container.appendChild(seconds);\n\n return {\n days,\n hours,\n minutes,\n seconds,\n };\n};\n","/*!\n * Project : simplyCountdown.js\n * Date : __SCD_BUILD_DATE__\n * License : MIT\n * Version : __SCD_VERSION__\n * Author : Vincent Loy-Serre\n * Contributors :\n * - Justin Beasley\n * - Nathan Smith\n * - Mehdi Rezaei\n * - mira01\n */\n\nimport type { CountdownParameters, CountdownSelector, CountdownState, CountdownController, CountdownControllerArray } from \"../types\";\nimport { createCountdown, updateCountdownSection } from \"./dom\";\n\nconst defaultParams: CountdownParameters = {\n year: 2024,\n month: 12,\n day: 25,\n hours: 0,\n minutes: 0,\n seconds: 0,\n words: {\n days: { lambda: (root, n) => (n > 1 ? root + \"s\" : root), root: \"day\" },\n hours: { lambda: (root, n) => (n > 1 ? root + \"s\" : root), root: \"hour\" },\n minutes: { lambda: (root, n) => (n > 1 ? root + \"s\" : root), root: \"minute\" },\n seconds: { lambda: (root, n) => (n > 1 ? root + \"s\" : root), root: \"second\" },\n },\n plural: true,\n inline: false,\n inlineSeparator: \", \",\n enableUtc: false,\n onEnd: () => {},\n refresh: 1000,\n inlineClass: \"simply-countdown-inline\",\n sectionClass: \"simply-section\",\n amountClass: \"simply-amount\",\n wordClass: \"simply-word\",\n zeroPad: false,\n countUp: false,\n removeZeroUnits: false,\n onStop: () => {},\n onResume: () => {},\n onUpdate: () => {},\n};\n\nconst isNodeList = (element: CountdownSelector): element is NodeListOf<HTMLElement> => {\n return element instanceof NodeList;\n};\n\ninterface TimeUnit {\n value: number;\n word: keyof CountdownParameters[\"words\"];\n element?: HTMLElement;\n}\n\n/**\n * Formats a time unit with optional zero padding and pluralization\n * @param unit - The time unit object containing value and word properties\n * @param params - The countdown parameters containing formatting options and word definitions\n * @returns A formatted string containing the value and pluralized word for the time unit\n * @example\n * // With zeroPad: true\n * formatTimeUnit({value: 5, word: 'days'}, params) // returns \"05 days\"\n * // With zeroPad: false\n * formatTimeUnit({value: 5, word: 'days'}, params) // returns \"5 days\"\n */\nfunction formatTimeUnit(unit: TimeUnit, params: CountdownParameters): string {\n const value = params.zeroPad ? String(unit.value).padStart(2, \"0\") : unit.value;\n return `${value} ${params.words[unit.word].lambda(params.words[unit.word].root, unit.value)}`;\n}\n\n/**\n * Determines whether a time unit should be displayed based on its value and the values of previous units\n * @param unit - The current time unit to evaluate\n * @param previousUnits - Array of time units that come before the current unit\n * @param params - Configuration parameters for the countdown\n * @returns True if the unit should be displayed, false otherwise\n *\n * If removeZeroUnits is false in params, always returns true.\n * Otherwise, returns true if either:\n * - The current unit value is not zero\n * - Any previous unit has a non-zero value\n */\nfunction shouldDisplay(unit: TimeUnit, previousUnits: TimeUnit[], params: CountdownParameters): boolean {\n if (!params.removeZeroUnits) return true;\n return unit.value !== 0 || previousUnits.some((u) => u.value !== 0);\n}\n\n/**\n * Displays the countdown timer inline within the specified HTML element.\n *\n * @param timeUnits - Array of time units containing values and labels for display\n * @param params - Configuration parameters for the countdown display\n * @param element - The HTML element where the countdown will be rendered\n *\n * @remarks\n * The function filters and formats time units based on display rules, then joins them with\n * the specified separator from params.inlineSeparator before setting the element's innerHTML.\n */\nfunction displayInline(timeUnits: TimeUnit[], params: CountdownParameters, element: HTMLElement): void {\n const displayStr = timeUnits\n .filter((unit, index) => shouldDisplay(unit, timeUnits.slice(0, index), params))\n .map((unit) => formatTimeUnit(unit as { value: number; word: keyof typeof params.words }, params))\n .join(params.inlineSeparator);\n\n element.innerHTML = displayStr;\n}\n\n/**\n * Updates the display of time units in the countdown based on their values and display conditions\n * @param timeUnits - Array of TimeUnit objects containing the time values and their corresponding words\n * @param params - Configuration parameters for the countdown display\n * @param countdown - DOM elements representing the countdown display sections\n * @returns void\n *\n * @remarks\n * This function iterates through each time unit and determines whether it should be shown based on:\n * - If it's the seconds unit (always shown)\n * - If it meets display criteria based on previous units\n *\n * For units that should be shown, it:\n * - Updates the display value (with optional zero padding)\n * - Updates the word label using the configured lambda function\n * - Shows the unit's DOM element\n *\n * For units that shouldn't be shown, it hides their DOM elements\n */\nfunction displayBlocks(timeUnits: TimeUnit[], params: CountdownParameters, countdown: any): void {\n timeUnits.forEach((unit, index) => {\n const shouldShow = unit.word === \"seconds\" || shouldDisplay(unit, timeUnits.slice(0, index), params);\n\n if (shouldShow) {\n updateCountdownSection(\n countdown[unit.word],\n params.zeroPad ? String(unit.value).padStart(2, \"0\") : unit.value,\n params.words[unit.word].lambda(params.words[unit.word].root, unit.value)\n );\n countdown[unit.word].style.display = \"\";\n } else {\n countdown[unit.word].style.display = \"none\";\n }\n });\n}\n\n/**\n * Creates a countdown instance that manages the countdown timer functionality.\n *\n * @param targetElement - The HTML element where the countdown will be rendered\n * @param parameters - Configuration parameters for the countdown\n *\n * @returns A controller object with methods to control the countdown:\n * - stopCountdown: Pauses the countdown and triggers onStop callback\n * - resumeCountdown: Resumes a paused countdown and triggers onResume callback\n * - updateCountdown: Updates countdown parameters and triggers onUpdate callback\n * - getState: Returns current state of the countdown\n */\nconst createCountdownInstance = (targetElement: HTMLElement, parameters: CountdownParameters): CountdownController => {\n let state: CountdownState = {\n isPaused: false,\n interval: null,\n targetDate: new Date(),\n };\n\n const getTargetDate = (params: CountdownParameters): Date => {\n return params.enableUtc\n ? new Date(Date.UTC(params.year, params.month - 1, params.day, params.hours, params.minutes, params.seconds))\n : new Date(params.year, params.month - 1, params.day, params.hours, params.minutes, params.seconds);\n };\n\n state.targetDate = getTargetDate(parameters);\n\n // Create span element for inline mode\n let inlineElement: HTMLElement | null = null;\n if (parameters.inline) {\n inlineElement = document.createElement(\"span\");\n inlineElement.className = parameters.inlineClass;\n targetElement.appendChild(inlineElement);\n }\n\n const countdown = parameters.inline\n ? null\n : createCountdown(targetElement, {\n sectionClass: parameters.sectionClass,\n amountClass: parameters.amountClass,\n wordClass: parameters.wordClass,\n });\n\n const refresh = () => {\n // Fix UTC current date handling\n const currentDate = parameters.enableUtc\n ? new Date(\n Date.UTC(\n new Date().getUTCFullYear(),\n new Date().getUTCMonth(),\n new Date().getUTCDate(),\n new Date().getUTCHours(),\n new Date().getUTCMinutes(),\n new Date().getUTCSeconds()\n )\n )\n : new Date();\n\n let diff = parameters.countUp ? currentDate.getTime() - state.targetDate.getTime() : state.targetDate.getTime() - currentDate.getTime();\n\n if (diff <= 0 && !parameters.countUp) {\n diff = 0;\n // Clear interval before calling onEnd to prevent multiple calls\n if (state.interval !== null) {\n clearInterval(state.interval);\n }\n\n if (parameters.onEnd) {\n parameters.onEnd();\n }\n }\n\n const days = Math.floor(diff / (1000 * 60 * 60 * 24));\n diff -= days * 1000 * 60 * 60 * 24;\n\n const hours = Math.floor(diff / (1000 * 60 * 60));\n diff -= hours * 1000 * 60 * 60;\n\n const minutes = Math.floor(diff / (1000 * 60));\n diff -= minutes * 1000 * 60;\n\n const seconds = Math.floor(diff / 1000);\n\n if (parameters.inline && inlineElement) {\n const timeUnits: TimeUnit[] = [\n { value: days, word: \"days\" as keyof CountdownParameters[\"words\"] },\n {\n value: hours,\n word: \"hours\" as keyof CountdownParameters[\"words\"],\n },\n {\n value: minutes,\n word: \"minutes\" as keyof CountdownParameters[\"words\"],\n },\n {\n value: seconds,\n word: \"seconds\" as keyof CountdownParameters[\"words\"],\n },\n ];\n displayInline(timeUnits, parameters, inlineElement);\n } else if (countdown) {\n const timeUnits: TimeUnit[] = [\n { value: days, word: \"days\" as keyof CountdownParameters[\"words\"] },\n {\n value: hours,\n word: \"hours\" as keyof CountdownParameters[\"words\"],\n },\n {\n value: minutes,\n word: \"minutes\" as keyof CountdownParameters[\"words\"],\n },\n {\n value: seconds,\n word: \"seconds\" as keyof CountdownParameters[\"words\"],\n },\n ];\n displayBlocks(timeUnits, parameters, countdown);\n }\n };\n\n const startInterval = () => {\n state.interval = setInterval(refresh, parameters.refresh);\n refresh();\n };\n\n const stopCountdown = () => {\n if (state.interval !== null) {\n clearInterval(state.interval);\n state.interval = null;\n }\n state.isPaused = true;\n parameters.onStop?.();\n };\n\n const resumeCountdown = () => {\n if (state.isPaused) {\n startInterval();\n state.isPaused = false;\n parameters.onResume?.();\n }\n };\n\n const updateCountdown = (newParams: Partial<CountdownParameters>) => {\n Object.assign(parameters, newParams);\n if (\n newParams.year !== undefined ||\n newParams.month !== undefined ||\n newParams.day !== undefined ||\n newParams.hours !== undefined ||\n newParams.minutes !== undefined ||\n newParams.seconds !== undefined\n ) {\n state.targetDate = getTargetDate(parameters);\n }\n\n parameters.onUpdate?.(newParams);\n\n if (!state.isPaused) {\n if (state.interval) {\n clearInterval(state.interval);\n }\n startInterval();\n }\n };\n\n const getState = () => ({ ...state });\n\n // Start the countdown\n startInterval();\n\n // Cleanup on element removal\n const observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n mutation.removedNodes.forEach((node) => {\n if (node === targetElement) {\n if (state.interval !== null) {\n clearInterval(state.interval);\n }\n observer.disconnect();\n }\n });\n });\n });\n\n if (targetElement.parentNode) {\n observer.observe(targetElement.parentNode, { childList: true });\n }\n\n // Return controller object\n return {\n stopCountdown,\n resumeCountdown,\n updateCountdown,\n getState,\n };\n};\n\n/**\n * Creates an enhanced array of countdown controllers with additional control methods.\n *\n * @param controllers - Array of individual countdown controllers to be combined\n * @returns An array of controllers enhanced with collective control methods:\n * - `stopCountdown()`: Stops all countdowns in the array\n * - `resumeCountdown()`: Resumes all countdowns in the array\n * - `updateCountdown(newParams)`: Updates all countdowns with new parameters\n * - `getState()`: Returns an array of states from all countdowns\n */\nconst createControllerArray = (controllers: CountdownController[]): CountdownControllerArray => {\n const array = controllers as CountdownControllerArray;\n\n array.stopCountdown = () => controllers.forEach((c) => c.stopCountdown());\n array.resumeCountdown = () => controllers.forEach((c) => c.resumeCountdown());\n array.updateCountdown = (newParams) => controllers.forEach((c) => c.updateCountdown(newParams));\n array.getState = () => controllers.map((c) => c.getState());\n\n return array;\n};\n\n/**\n * Creates a countdown timer on specified HTML elements\n * @param element - A CSS selector string, HTMLElement, or NodeList targeting the countdown container(s)\n * @param args - Optional configuration parameters for the countdown\n * @returns A CountdownController for single element or CountdownControllerArray for multiple elements\n */\nconst simplyCountdown = (\n element: CountdownSelector,\n args: Partial<CountdownParameters> = defaultParams\n): CountdownController | CountdownControllerArray => {\n const parameters: CountdownParameters = { ...defaultParams, ...args };\n\n if (typeof element === \"string\") {\n const elements = document.querySelectorAll<HTMLElement>(element);\n const controllers = Array.from(elements).map((el) => createCountdownInstance(el, parameters));\n return controllers.length === 1 ? controllers[0] : createControllerArray(controllers);\n }\n\n if (isNodeList(element)) {\n const controllers = Array.from(element).map((el) => createCountdownInstance(el, parameters));\n return controllers.length === 1 ? controllers[0] : createControllerArray(controllers);\n }\n\n return createCountdownInstance(element, parameters);\n};\n\nexport default simplyCountdown;\n","import simplyCountdownCore from \"./simplyCountdown\";\n\ndeclare const define: {\n (factory: () => any): void;\n amd: boolean;\n};\n\nif (typeof define === \"function\" && define.amd) {\n // AMD\n define(function () {\n return simplyCountdownCore;\n });\n} else if (typeof module === \"object\" && module.exports) {\n // Node\n module.exports = simplyCountdownCore;\n} else {\n // Browser\n (window as any).simplyCountdown = simplyCountdownCore;\n}\n\n// Export for Vite/Rollup\nexport default simplyCountdownCore;\n"],"names":["createCountdownSection","sectionClass","amountClass","wordClass","amount","word","params","section","document","createElement","className","wrap","amount_elem","word_elem","textContent","String","appendChild","defaultParams","year","month","day","hours","minutes","seconds","words","days","lambda","root","n","plural","inline","inlineSeparator","enableUtc","onEnd","refresh","inlineClass","zeroPad","countUp","removeZeroUnits","onStop","onResume","onUpdate","shouldDisplay","unit","previousUnits","value","some","u","displayInline","timeUnits","element","displayStr","filter","index","slice","map","padStart","formatTimeUnit","join","innerHTML","displayBlocks","countdown","forEach","amountElement","querySelector","wordElement","updateCountdownSection","style","display","createCountdownInstance","targetElement","parameters","state","isPaused","interval","targetDate","Date","getTargetDate","UTC","inlineElement","container","amountCls","wordCls","createCountdown","currentDate","getUTCFullYear","getUTCMonth","getUTCDate","getUTCHours","getUTCMinutes","getUTCSeconds","diff","getTime","clearInterval","Math","floor","startInterval","setInterval","observer","MutationObserver","mutations","mutation","removedNodes","node","disconnect","parentNode","observe","childList","stopCountdown","_a","call","resumeCountdown","updateCountdown","newParams","Object","assign","getState","createControllerArray","controllers","array","c","simplyCountdown","args","elements","querySelectorAll","Array","from","el","length","NodeList","isNodeList","define","amd","simplyCountdownCore","module","exports","window"],"mappings":"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"}
Binary file
Binary file
@@ -2,7 +2,7 @@
2
2
 
3
3
  {% can_show_item value.visible_for as csi %}
4
4
  {% if csi %}
5
- <a href="{% if request.LANGUAGE_CODE and request.LANGUAGE_CODE != 'en' %}/{{ request.LANGUAGE_CODE }}{% endif %}{{ self.url }}"
5
+ <a href="{% if request.LANGUAGE_CODE and request.LANGUAGE_CODE|not_starts_with:'en' %}/{{ request.LANGUAGE_CODE }}{% endif %}{{ self.url }}"
6
6
  {% if settings.cjkcms.AnalyticsSettings.ga_track_button_clicks %}
7
7
  data-ga-event-category='{{self.settings.ga_tracking_event_category|default:"Button"}}'
8
8
  data-ga-event-label='{{self.settings.ga_tracking_event_label|default:self.button_title}}'
@@ -0,0 +1,24 @@
1
+ {% load wagtailcore_tags static %}
2
+
3
+ {% block block_render %}
4
+ {% with 'vendor/simplycountdown/css/'|add:self.theme|add:'.css' as theme_css %}
5
+ <link rel="stylesheet" href="{% static theme_css %}">
6
+ {% endwith %}
7
+ {% if self.url %}<a href="{{self.url}}" class="text-decoration-none">{% endif %}
8
+ <div class="simply-countdown-{{self.theme}} {%if self.settings.custom_css_class%}{{self.settings.custom_css_class}}{% endif %}" id="mycountdown">
9
+ {% if self.title %}<h3 class="w-100 text-center">{{ self.title }}</h3>{% endif %}
10
+ </div>
11
+ {% if self.url %}</a>{% endif %}
12
+ <script src="{% static 'vendor/simplycountdown/js/simplyCountdown.umd.js' %}"></script>
13
+ <script>
14
+ simplyCountdown("#mycountdown", {
15
+ year: {{ year }},
16
+ month: {{ month }},
17
+ day: {{ day }},
18
+ hours: {{ hour }},
19
+ minutes: {{ minute }},
20
+ seconds: {{ second }},
21
+ enableUtc: true,
22
+ });
23
+ </script>
24
+ {% endblock %}
@@ -318,3 +318,8 @@ def is_not_page(model):
318
318
  return False
319
319
  else:
320
320
  return True
321
+
322
+
323
+ @register.filter(name="not_starts_with")
324
+ def not_starts_with(value, arg):
325
+ return not value.startswith(arg)
@@ -0,0 +1,100 @@
1
+ import pytest
2
+ from django.test import Client, TestCase, override_settings
3
+ from wagtail.models import Page
4
+ from cjkcms.models.cms_models import ArticlePage
5
+ from datetime import datetime, timedelta, timezone
6
+
7
+
8
+ @override_settings(
9
+ STORAGES={
10
+ "default": {
11
+ "BACKEND": "django.core.files.storage.FileSystemStorage",
12
+ },
13
+ "staticfiles": {
14
+ "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
15
+ },
16
+ }
17
+ )
18
+ @pytest.mark.django_db
19
+ class TestCountdownBlock(TestCase):
20
+ def setUp(self):
21
+ self.client = Client()
22
+ self.create_article_page()
23
+
24
+ def create_article_page(self):
25
+ home_page = Page.objects.get(path="00010001")
26
+ article_page = ArticlePage(title="Test Article", body=None)
27
+ home_page.add_child(instance=article_page)
28
+ article_page.save_revision().publish()
29
+
30
+ def set_article_body(self, content) -> None:
31
+ article_page = ArticlePage.objects.get(title="Test Article")
32
+ article_page.body = content
33
+ article_page.save_revision().publish()
34
+
35
+ def test_css_theme_title(self):
36
+ block_content = [
37
+ {
38
+ "type": "countdown",
39
+ "value": {
40
+ "title": "Counter Title",
41
+ "theme": "losange",
42
+ "settings": {"custom_css_class": "my-custom-class"},
43
+ "start_date": "2029-01-01 00:00",
44
+ },
45
+ "id": "countdown-block",
46
+ }
47
+ ]
48
+ self.set_article_body(block_content)
49
+ response = self.client.get("/test-article/")
50
+ self.assertContains(response, "my-custom-class")
51
+ self.assertNotContains(response, "my-other-class")
52
+ self.assertContains(response, "losange")
53
+ self.assertContains(response, "Counter Title")
54
+ self.assertNotContains(response, "<a href=")
55
+
56
+ def test_url(self):
57
+ block_content = [
58
+ {
59
+ "type": "countdown",
60
+ "value": {
61
+ "theme": "light",
62
+ "url": "https://example.com",
63
+ "start_date": "2029-01-01 00:00",
64
+ "timezone": "UTC",
65
+ },
66
+ "id": "countdown-block2",
67
+ }
68
+ ]
69
+ self.set_article_body(block_content)
70
+ response = self.client.get("/test-article/")
71
+ self.assertContains(response, '<a href="https://example.com"')
72
+
73
+ def test_time(self):
74
+ # generate start date that is one in the future
75
+
76
+ # Get the current UTC time
77
+ current_utc_time = datetime.now(timezone.utc)
78
+ # Add one minute to the current UTC time
79
+ one_minute_ahead = current_utc_time + timedelta(minutes=1)
80
+ # Remove timezone info from the one_minute_ahead datetime
81
+ one_minute_ahead_naive = one_minute_ahead.replace(tzinfo=None)
82
+
83
+ block_content = [
84
+ {
85
+ "type": "countdown",
86
+ "value": {
87
+ "theme": "light",
88
+ "start_date": one_minute_ahead_naive.strftime("%Y-%m-%d %H:%M"),
89
+ "timezone": "UTC",
90
+ },
91
+ "id": "countdown-block3",
92
+ }
93
+ ]
94
+ self.set_article_body(block_content)
95
+ response = self.client.get("/test-article/")
96
+ self.assertContains(response, "year: " + str(one_minute_ahead.year))
97
+ self.assertContains(response, "month: " + str(one_minute_ahead.month))
98
+ self.assertContains(response, "day: " + str(one_minute_ahead.day))
99
+ self.assertContains(response, "hours: " + str(one_minute_ahead.hour))
100
+ self.assertContains(response, "minutes: " + str(one_minute_ahead.minute))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wagtail-cjkcms
3
- Version: 24.11.1
3
+ Version: 24.12.2
4
4
  Summary: Wagtail Content Management System, installable as a Django app into any Wagtail 4.1.x/5.x/6.x site.
5
5
  Author-email: Grzegorz Krol <gk@cjk.pl>
6
6
  License: BSD-3-Clause
@@ -1,4 +1,5 @@
1
- cjkcms/__init__.py,sha256=Nno1oucYE_Mhlri7FYkxOZQqWlcJ6E7_FU2Cm3nH4m4,273
1
+ cjkcms/.DS_Store,sha256=cYcT7MpEwyMj1-CAvcue4ODbL87U2KGsmN7HYD4O8SY,6148
2
+ cjkcms/__init__.py,sha256=ZsUuUlcExnTWNhB9GZKCu2i_Ah9oeimsNC_IZ0Rpr6s,273
2
3
  cjkcms/apps.py,sha256=VA5Z1YerImetvN8KsjPTMSn1fSo6O1JkBJdK5y5ubJY,173
3
4
  cjkcms/fields.py,sha256=dE0DuNIjX7jhA-5GjSmR2l66EDH2kq3vuxL9WyRALCY,3191
4
5
  cjkcms/forms.py,sha256=_uu_FR8odz40lD-Rmw0tlK7-xxxa8THHfV2-1ZJYsIM,361
@@ -14,13 +15,14 @@ cjkcms/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
15
  cjkcms/api/mailchimp.py,sha256=pufnnu8n-c6kkWNKy-EsRLW5LLBn8_TmYrnRSQCPFdY,2832
15
16
  cjkcms/bin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
17
  cjkcms/bin/cjkcms.py,sha256=i11hhB11COQhTk05y7mkeIkUYcFjhI8-QxLkN3tCxgg,5763
17
- cjkcms/blocks/__init__.py,sha256=cp7D9NSxF9HOEQN_h0GWMGFoZfhBYhDpCosZ7Gqi_mo,3459
18
+ cjkcms/blocks/__init__.py,sha256=a54EtWyH8UPqszlVEeOtFCvBW2WmbaW1vR4sZuN9Hf0,3542
18
19
  cjkcms/blocks/base_blocks.py,sha256=uKp6QO3iOPT4P0H0yOumvL7faPvLQK9Dj-D8iqlvqQ4,11616
19
20
  cjkcms/blocks/content_blocks.py,sha256=db_CNBqpKdAq1e9Y4AdpRm1077ANIWD8DzqG56_rSNs,10098
20
21
  cjkcms/blocks/html_blocks.py,sha256=rXdR1uxFYDYjOXpxndItxacWstiME8CdqZgB6d5qAYE,9543
21
22
  cjkcms/blocks/layout_blocks.py,sha256=n2oVyL-ZQQaEA00HU6YraR59YF065o-OK7WuAahGuiw,3406
22
23
  cjkcms/blocks/searchable_html_block.py,sha256=i1rWv4vwwvZ9fxkASwPKl87-TqVHkXOFyohH3ve7pYk,171
23
24
  cjkcms/blocks/content/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ cjkcms/blocks/content/countdown.py,sha256=KWutgbPY_N49vrxqUPjbir-MgN0ro5u8WVXD8MyJUbI,3342
24
26
  cjkcms/blocks/content/events.py,sha256=H3uIl4Gxfsm8yjdfaEMRLcNs5-HkoMZUP1qkxPd5Z9Q,1967
25
27
  cjkcms/draftail/__init__.py,sha256=4-DXyDcnvAacmOzRW5IzmNb28kU71PJ18Q89vkxCv_8,240
26
28
  cjkcms/draftail/draftail_extensions.py,sha256=Grf3vkuqyygt7vn3Fp1ALXLxjgSsYZ4-rLH4R8eFIEU,3250
@@ -32,8 +34,6 @@ cjkcms/management/commands/import-csv.py,sha256=5IR_GHVhuHdb0UX_TNLe4OuKhwRmKjU3
32
34
  cjkcms/management/commands/init-collections.py,sha256=bTDVz3RyXUoCUXv-d2P3JWjySw0INvO_14IfNmPEG9A,951
33
35
  cjkcms/management/commands/init-navbar.py,sha256=rO0O1MjzfvmnQoZllhY3g6KOHT3nFt5UR0WkIsb-4PA,3560
34
36
  cjkcms/management/commands/init-website.py,sha256=DJPREmnv3srarhNWbiowluKAuUoa-PXDlENQQgnWZPY,3820
35
- cjkcms/media/images/test.original.png,sha256=nLMtadXZhXXbt6DTm5enrysKX7cfWiUudtbS2X7mSzI,1938
36
- cjkcms/media/original_images/test.png,sha256=xJDvcufuQ-AM1HT-zgMxYEORko4rdK_8MSHU-puJNW8,2306
37
37
  cjkcms/migrations/0001_initial.py,sha256=hiDQKRqmKk65tS8jyXRRfffWLzLMB7P0r3qEqu88jAM,2070677
38
38
  cjkcms/migrations/0002_alter_body_to_cjkcmsstreamfield.py,sha256=QYPXCirKSBBwB4JNcei_OhEx856Cq0_S-7ZXmEtcCAI,924
39
39
  cjkcms/migrations/0003_alter_footer_content_alter_navbar_menu_items.py,sha256=N5vRtKBIlQ99zbBKTFoVAVeMH_K192c2dVVYOvHD4Nc,727
@@ -173,15 +173,24 @@ cjkcms/static/vendor/mdb/css/mdb.min.css,sha256=NwSiVkXzh8wtWxshP59CXHGRsNaM03bm
173
173
  cjkcms/static/vendor/mdb/css/mdb.min.css.map,sha256=HCd-vGDs-t7EinsTSmawI-CdC92HmydrH0TqlB4Oh4s,546228
174
174
  cjkcms/static/vendor/mdb/js/mdb.umd.min.js,sha256=6ExxHAv6V4GggQXwu1gkXc4MHtdiqKgVwBQ2m1HGr2M,124534
175
175
  cjkcms/static/vendor/mdb/js/mdb.umd.min.js.map,sha256=1k9rRQNB3hrVj47Anhg19MtXioMnuffFMh34NEyrBcY,502496
176
+ cjkcms/static/vendor/simplycountdown/css/circle.css,sha256=p8XghcW_i3DReRzmivluCPvvTeufVcyzpQRlHtYPxwI,1632
177
+ cjkcms/static/vendor/simplycountdown/css/cyber.css,sha256=OECAvPFLHuUkgv9ENP27SzVaCimFS0T7g_5jT0l5TTg,3813
178
+ cjkcms/static/vendor/simplycountdown/css/dark.css,sha256=VEMMr_JIZ303FlNVc5j-_BstLolM2Ru-gZ0MEHUiNW0,1899
179
+ cjkcms/static/vendor/simplycountdown/css/light.css,sha256=WXbRsGaWA-xmc-tMeTNGvx6-FvLqgnGz67UvJv3OYN0,1926
180
+ cjkcms/static/vendor/simplycountdown/css/losange.css,sha256=qzyTDoj2LhR6JMQB7OAe3nwG1Wm3Te4rnDmq1qRBw5s,1803
181
+ cjkcms/static/vendor/simplycountdown/js/simplyCountdown.umd.js,sha256=Jiw45EkrYMAywPxoUK0G7sUaZWZo6Aucpw5gt8YIl7w,5024
182
+ cjkcms/static/vendor/simplycountdown/js/simplyCountdown.umd.js.map,sha256=qunXuRwA6mOaCihYJfsIg7J72p3XaurneVGSTNPez7Y,25873
183
+ cjkcms/templates/.DS_Store,sha256=dyZnb39fKIIkLjeDh-Q3jgmLIVt624Ouh-D6Bg_KNAU,6148
176
184
  cjkcms/templates/404.html,sha256=GnIFZoXMcFzz_UTMChOgbO6-IIWQZKaAom7OJXn6dao,3245
177
185
  cjkcms/templates/500.html,sha256=YWYel2g2SDKLwSv8C9VLPzVvkcRLo6X9WYwWjxnfz0U,4802
186
+ cjkcms/templates/cjkcms/.DS_Store,sha256=9gfOq7SmBsVA0HbZiVkZmy0Gc2DBCrPvHirRQ70X47Q,6148
178
187
  cjkcms/templates/cjkcms/robots.txt,sha256=669-RWM9DZYUfyxUvl2Fxn6pcZ_7Efbb7HeZYoR0DWo,92
179
188
  cjkcms/templates/cjkcms/blocks/accordion_block.html,sha256=9gsMZMflXqdYcFVqf8YOsyb3YYHgC26Sug_tzGvc6N8,1443
180
189
  cjkcms/templates/cjkcms/blocks/article_block_card.html,sha256=37Xb0XNGVSyWP8gXVGh742eZmW-3hFSmEAfCe5QOrvo,974
181
190
  cjkcms/templates/cjkcms/blocks/article_masonry_card.html,sha256=rW1fDJrERAw_1u391An7F8mvqmrvM2xLcXS9gAgfwuM,1132
182
191
  cjkcms/templates/cjkcms/blocks/base_block.html,sha256=i1iRaLNqVF5Cd_Tv56TbXrA8uBCChnRMRagN047Rx2I,188
183
192
  cjkcms/templates/cjkcms/blocks/base_link_block.html,sha256=EznK9jWFFC_k8mEyi3W_h0w3CNvB_jubYsTawAEvivY,2675
184
- cjkcms/templates/cjkcms/blocks/button_block.html,sha256=cNovMRdHugaR0gQhYws-Mm9PiJHZAWF1MlE620HOJUQ,862
193
+ cjkcms/templates/cjkcms/blocks/button_block.html,sha256=skwQN6x0FWBYGEQbX1hIg1prgO0AarmzjzdsjmPyvdg,875
185
194
  cjkcms/templates/cjkcms/blocks/card_block.html,sha256=Z5wzPM7-X3QWx5B_CAO2e5ei9OyNwUD4m4h_HV2Bj5c,746
186
195
  cjkcms/templates/cjkcms/blocks/card_blurb.html,sha256=QUIK1Xv7cIvTA17wXSp0FKCSobQhBWqLqPIWMNvd2u8,856
187
196
  cjkcms/templates/cjkcms/blocks/card_foot.html,sha256=VPGJRBTAf_n73wS_nNryccnrmrGNGy9NodPxgI_3ioc,786
@@ -198,6 +207,7 @@ cjkcms/templates/cjkcms/blocks/cardgrid_group.html,sha256=mCOBw0wmTOyHvRXrngI-lw
198
207
  cjkcms/templates/cjkcms/blocks/cardgrid_zero.html,sha256=lECaWt-D_N1zd5U8xnYWu0H-M-vNnMnIvzlulBag_hg,276
199
208
  cjkcms/templates/cjkcms/blocks/carousel_block.html,sha256=XC04uEPWjQKmN7dHoQVv9NmFPkBxLhCpwTzvVGeXUwk,2698
200
209
  cjkcms/templates/cjkcms/blocks/column_block.html,sha256=7aiPizV-MrXS2LyV_fP1aCpNoC0nNAQphyVuAWbi2SI,406
210
+ cjkcms/templates/cjkcms/blocks/countdown.html,sha256=blU12tkfSUp1G3W7bEK0xBClVgj-baeCk9qGkWIpb9E,921
201
211
  cjkcms/templates/cjkcms/blocks/document_link_block.html,sha256=cEJERsbEF4sSLyyBRSHtiePwc-Q9S02dF0BZo_CThZ0,137
202
212
  cjkcms/templates/cjkcms/blocks/download_block.html,sha256=0uslQsNRhg0XYhLijfrToAFiMVQ_SsOBTxcKRYXScbc,920
203
213
  cjkcms/templates/cjkcms/blocks/embed_video_block.html,sha256=qHstCQwbgTykxWUqfH81oOF37gfPa57r47_QiQ8ocWQ,103
@@ -305,7 +315,7 @@ cjkcms/templates/wagtailadmin/shared/cr_main_nav_2fix.html,sha256=BAhkDE8_8KbhUO
305
315
  cjkcms/templates/wagtailadmin/tables/thumbnail_cell.html,sha256=RzMT-tBnnDOgL-zexKanZTTpCEX1bMybFL2p_zvOEV4,578
306
316
  cjkcms/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
307
317
  cjkcms/templatetags/auth_extras.py,sha256=IIxQ5n9FaQVZmhW-yW1XM5p2OjIemtqVoX-O-UcCns8,327
308
- cjkcms/templatetags/cjkcms_tags.py,sha256=cY-FqY5kOmsZ1loldSTHWPEbpCgCKbBXhp3P1X2XICU,9054
318
+ cjkcms/templatetags/cjkcms_tags.py,sha256=qpJrxMYJKz6pQeuoMx5YBP_xkMcV65fwQCEplAV-WNM,9166
309
319
  cjkcms/templatetags/friendly_loader.py,sha256=Zwopb9NNNN6IuDJCMFlwKuhmJC0hi4uTPEZSAxeakYY,4962
310
320
  cjkcms/templatetags/gravatar.py,sha256=JG5MB6HUFso15J8gZ_te5FTMYAuo4km8rzMKKvLLh-E,1127
311
321
  cjkcms/templatetags/txtutils_tags.py,sha256=UMojdiLt6Jpijc-2QLusPc-qXX9bqFZf0JbqqPsfnWQ,1223
@@ -315,6 +325,7 @@ cjkcms/tests/settings.py,sha256=WVu7tOcUH1E_DJ6YOEfi5_r5tJobUbX9O0VAmVl4ICg,2556
315
325
  cjkcms/tests/test_advsettings.py,sha256=6EngxFbUtwpaKDrvdLdCR6ONfHR3K1XGpOYKZJTHBUg,6906
316
326
  cjkcms/tests/test_articlepages.py,sha256=7V7tr2kCKiEU1y36PlB9yoP0tmSDb8cchf8VYof3GGM,4226
317
327
  cjkcms/tests/test_bin.py,sha256=z-6vMYYqhv18UO00sUPrNpLLue0mbRr5vzqisu7UKAY,3506
328
+ cjkcms/tests/test_countdown_block.py,sha256=83RgYXvOLErcswXg13WRPD-Lf5VAykx_YRb27o2II4c,3712
318
329
  cjkcms/tests/test_draftail_extensions.py,sha256=8WAf8LdvSxW7kgtJaXQ8V3rSRNkzRDc-JGnlKOWZr3k,2364
319
330
  cjkcms/tests/test_finders_oembed.py,sha256=J-dG3aTsO2KXnUA0o4yKHh_r5Za9v_8gcXJQGwJrXpI,2489
320
331
  cjkcms/tests/test_gravatar.py,sha256=UWu1cVi3Gj96yqeQu795gw6FVPbZ44eCkkH1NGEGgBo,2629
@@ -325,22 +336,16 @@ cjkcms/tests/test_urls.py,sha256=otiKZcs1WLDQM6AOfcdZgsOGDwea1qS3VEc8Yy-FV-Q,288
325
336
  cjkcms/tests/test_webpage.py,sha256=PvXeXbawigObsdi_YpQNuHFx3Lqi6wM3ktVHZsxYbr4,1520
326
337
  cjkcms/tests/urls.py,sha256=_ksKz7HBHJtQK3HxC9cmJMX_dt6n4alx3FXjcL-cu28,850
327
338
  cjkcms/tests/media/images/test.original.png,sha256=nLMtadXZhXXbt6DTm5enrysKX7cfWiUudtbS2X7mSzI,1938
328
- cjkcms/tests/media/images/test_oKdmwQn.original.png,sha256=nLMtadXZhXXbt6DTm5enrysKX7cfWiUudtbS2X7mSzI,1938
329
- cjkcms/tests/media/images/test_otfQve2.original.png,sha256=nLMtadXZhXXbt6DTm5enrysKX7cfWiUudtbS2X7mSzI,1938
330
- cjkcms/tests/media/images/test_qFhTLcX.original.png,sha256=nLMtadXZhXXbt6DTm5enrysKX7cfWiUudtbS2X7mSzI,1938
331
339
  cjkcms/tests/media/original_images/test.png,sha256=xJDvcufuQ-AM1HT-zgMxYEORko4rdK_8MSHU-puJNW8,2306
332
- cjkcms/tests/media/original_images/test_oKdmwQn.png,sha256=xJDvcufuQ-AM1HT-zgMxYEORko4rdK_8MSHU-puJNW8,2306
333
- cjkcms/tests/media/original_images/test_otfQve2.png,sha256=xJDvcufuQ-AM1HT-zgMxYEORko4rdK_8MSHU-puJNW8,2306
334
- cjkcms/tests/media/original_images/test_qFhTLcX.png,sha256=xJDvcufuQ-AM1HT-zgMxYEORko4rdK_8MSHU-puJNW8,2306
335
340
  cjkcms/tests/testapp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
336
341
  cjkcms/tests/testapp/apps.py,sha256=EwyrkWTu-_OoLoERBTlqkqfPIIrEsbHY3kbCxgrv_7I,169
337
342
  cjkcms/tests/testapp/models.py,sha256=Rkn9KHrGbLzrKjP4y_gwtXma1_fJOZNU7ekb689fJEU,488
338
343
  cjkcms/tests/testapp/migrations/0001_initial.py,sha256=hxr-r-42IQEGr_OsZkxXXCW7wbxAHuI_OLOkn-seJUU,4942
339
344
  cjkcms/tests/testapp/migrations/0002_create_homepage.py,sha256=EfsxHh1oyqwahW9RVpTvaRDx_CHtFSJQahKEr7XC5Gg,1999
340
345
  cjkcms/tests/testapp/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
341
- wagtail_cjkcms-24.11.1.dist-info/LICENSE,sha256=KHsCh1fKOZzvcKe1a9h3FlDjTjK_UurO3wHK55TnHHo,1538
342
- wagtail_cjkcms-24.11.1.dist-info/METADATA,sha256=MWbY67DufZtE0iZJ5R_n0YaMOBKnyAeiv-RGhQBdtMo,3107
343
- wagtail_cjkcms-24.11.1.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109
344
- wagtail_cjkcms-24.11.1.dist-info/entry_points.txt,sha256=FzoiFENdZ1uebNztyz6GlswkumQspd5VjWbR9MUIH_8,50
345
- wagtail_cjkcms-24.11.1.dist-info/top_level.txt,sha256=8wJGOGo1pG5nO5akfcMzA7i3ndj5868I8w35vTT0JJM,7
346
- wagtail_cjkcms-24.11.1.dist-info/RECORD,,
346
+ wagtail_cjkcms-24.12.2.dist-info/LICENSE,sha256=KHsCh1fKOZzvcKe1a9h3FlDjTjK_UurO3wHK55TnHHo,1538
347
+ wagtail_cjkcms-24.12.2.dist-info/METADATA,sha256=7xCQjQfxWjcZtPgYzcAWemdjjn937AzzQIonjnQMkfg,3107
348
+ wagtail_cjkcms-24.12.2.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109
349
+ wagtail_cjkcms-24.12.2.dist-info/entry_points.txt,sha256=FzoiFENdZ1uebNztyz6GlswkumQspd5VjWbR9MUIH_8,50
350
+ wagtail_cjkcms-24.12.2.dist-info/top_level.txt,sha256=8wJGOGo1pG5nO5akfcMzA7i3ndj5868I8w35vTT0JJM,7
351
+ wagtail_cjkcms-24.12.2.dist-info/RECORD,,
Binary file
Binary file