jekyll-bear-theme 0.2.1 → 0.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0aea73bf2945806e91fd295522999311b1742e678325d80c0cf2a8f1fe9ffe08
4
- data.tar.gz: 48abae5a7748870c70172c3502d4d405495ef32515e26d7ecae275c2ea8842da
3
+ metadata.gz: 3ff08eadac46e03fb1806ee17aa05f1c3e781adc9a37a63c9b2fe6d8091e4e09
4
+ data.tar.gz: 2f733ffa2737c15a5a922910b38d18d2cd2418911b726fbc38f8e33918d76aa4
5
5
  SHA512:
6
- metadata.gz: f2364bd20a3a958a9a99d1286dfa8a96057955469fd316d1db7b9a5ba0c034ee7007ef1d8d957c5664747d1ae28fa4f9011040c33cb5f2bca9337bc33e616342
7
- data.tar.gz: b494eae2cb5b9b83a598068c57d4ec166bcd13c8f911eb2a5b98a6f71ff18290e4dc3d83753024c6e507bbfaffd53721d48e6918ea6f064611615dc5698f1b89
6
+ metadata.gz: 2392b39ce303ccb1b832628290937c58f862ea5d005807d0b3ea389ae1c71fde48dada77419c5d165710f9f24db1f9c22660c050b9ac6a5dd2cb88ddc35fd759
7
+ data.tar.gz: 4c3ff1cb58b97b95aa1d8d3ec94dcc18dded2f7a2526e038ef4012a801f8a0394fb57cbb211b31faadfff1c662d8e4b6ffefcd40007f2babb0fba8c084fe1596
data/README.md CHANGED
@@ -122,6 +122,18 @@ Use them as templates for your front matter.
122
122
  >To test your theme, run `bundle exec jekyll serve` and open your browser at `http://localhost:4000`.
123
123
 
124
124
 
125
+ ## Recent Updates: Life in Weeks Interactive Carousel
126
+
127
+ - The **Life in Weeks** page now features an interactive carousel blockquote above the grid, showing a key event from your life.
128
+ - Up/down arrows let you cycle through events. The week number, event name, and description are shown, with the week number highlighted.
129
+ - As you change the quote, the corresponding week in the grid pulses, visually connecting the event to its week.
130
+ - The quote area has a fixed height and is vertically centered, so the grid never shifts as you browse events.
131
+ - The grid is fully non-interactive (no tooltips, no pointer/question mark cursor), for a clean and minimal look.
132
+ - The carousel arrows are styled to match the theme and do not show a highlight on click.
133
+ - All code is lean and efficient: no extra network requests, no heavy JS, and all data is embedded at build time for instant loading.
134
+
135
+ See `life.md`, `_layouts/life-in-weeks.html`, and `assets/life-carousel.js` for implementation details.
136
+
125
137
  ## Contributing
126
138
 
127
139
  Bug reports and pull requests are welcome on GitHub at https://github.com/knhash/jekyllBear. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
@@ -20,7 +20,34 @@ layout: compress
20
20
  {% assign start_day = split_start[2] %}
21
21
  {% assign end_year = page.end_year | plus: 0 %}
22
22
 
23
- <div class="weeks-grid">
23
+ <!-- Carousel Blockquote Section -->
24
+ <div id="life-carousel-container" style="display: flex; align-items: center; margin: 2.2em 0 1.7em 0;" data-start-date="{{ page.start_date }}">
25
+ <div style="display: flex; flex-direction: column; align-items: center; margin-right: 1em;">
26
+ <button id="life-carousel-up" aria-label="Previous event" style="background: none; border: none; cursor: pointer; font-size: 1.5em; line-height: 1; padding: 0.2em;">
27
+ <span aria-hidden="true">&#9650;</span>
28
+ </button>
29
+ <button id="life-carousel-down" aria-label="Next event" style="background: none; border: none; cursor: pointer; font-size: 1.5em; line-height: 1; padding: 0.2em;">
30
+ <span aria-hidden="true">&#9660;</span>
31
+ </button>
32
+ </div>
33
+ <blockquote style="flex: 1; margin: 0; font-size: 1.1em; min-height: 5em; max-width: 100%; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; line-height: 1.5; font-style: normal;">
34
+ <span id="life-carousel-quote"></span>
35
+ <span id="life-carousel-meta" style="font-size: 0.95em; color: var(--main-color); margin-top: 0.5em;"></span>
36
+ </blockquote>
37
+ </div>
38
+ {% capture events_json %}[
39
+ {% assign first = true %}
40
+ {% for event_date in data %}
41
+ {% assign date = event_date[0] %}
42
+ {% for event in event_date[1] %}
43
+ {% unless first %},{% endunless %}{"name":{{ event.name | jsonify }},"desc":{{ event.desc | jsonify }},"date":{{ date | jsonify }}}
44
+ {% assign first = false %}
45
+ {% endfor %}
46
+ {% endfor %}
47
+ ]{% endcapture %}
48
+ <script id="life-in-weeks-events-json" type="application/json">{{ events_json | strip }}</script>
49
+ <script src="{{ "/assets/life-carousel.js" | relative_url }}"></script>
50
+ <div class="weeks-grid" style="margin-top: 1.7em;">
24
51
  {% assign total_years = end_year | minus: start_year | plus: 1 %}
25
52
  {% assign total_weeks = total_years | times: 52 %}
26
53
  {% if total_weeks > 0 %}
@@ -67,9 +94,9 @@ layout: compress
67
94
  {% assign is_current = true %}
68
95
  {% endif %}
69
96
  {% assign decade_mod = decade | modulo: 2 %}
70
- <div class="week decade-{{ decade_mod }}{% if week_has_events %} has-events{% endif %}{% if is_future %} future{% endif %}{% if is_current %} current{% endif %}"
71
- {% if week_has_events %}data-event="{{ week_tooltip | strip }}"{% endif %}>
72
- {% if week_has_events %}{{ week_events | strip }}{% endif %}
97
+ <div class="week decade-{{ decade_mod }}{% if week_has_events %} has-events{% endif %}{% if is_future %} future{% endif %}{% if is_current %} current{% endif %}"
98
+ data-week-number="{{ week_index }}">
99
+ <!-- No event text, just highlight -->
73
100
  </div>
74
101
  {% assign week_index = week_index | plus: 1 %}
75
102
  {% endfor %}
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,93 @@
1
+ // Carousel logic for life-in-weeks blockquote
2
+ (function() {
3
+ let currentIndex = 0;
4
+
5
+ // Parse events from embedded JSON
6
+ function loadEventsFromJson() {
7
+ var jsonTag = document.getElementById('life-in-weeks-events-json');
8
+ if (jsonTag) {
9
+ try {
10
+ var jsonStr = jsonTag.textContent.trim();
11
+ window.lifeInWeeksEvents = JSON.parse(jsonStr);
12
+ } catch (e) {
13
+ window.lifeInWeeksEvents = [];
14
+ }
15
+ }
16
+ }
17
+
18
+ function getWeekNumberSinceBirth(eventDateStr) {
19
+ // Get start_date from a data attribute on the container
20
+ const container = document.getElementById('life-carousel-container');
21
+ const startDateStr = container ? container.getAttribute('data-start-date') : null;
22
+ if (!startDateStr) return '?';
23
+ const start = new Date(startDateStr);
24
+ const eventDate = new Date(eventDateStr);
25
+ if (isNaN(start) || isNaN(eventDate)) return '?';
26
+ const diffMs = eventDate - start;
27
+ const weekNum = Math.floor(diffMs / (1000 * 60 * 60 * 24 * 7)) + 1;
28
+ return weekNum;
29
+ }
30
+
31
+ function updateCarousel() {
32
+ const events = window.lifeInWeeksEvents || [];
33
+ const quote = document.getElementById('life-carousel-quote');
34
+ const meta = document.getElementById('life-carousel-meta');
35
+ // Remove pulse from all weeks
36
+ document.querySelectorAll('.week.carousel-pulse').forEach(el => {
37
+ el.classList.remove('carousel-pulse');
38
+ });
39
+ if (!events.length) {
40
+ quote.textContent = 'No events to display.';
41
+ meta.textContent = '';
42
+ return;
43
+ }
44
+ if (currentIndex >= events.length) currentIndex = 0;
45
+ if (currentIndex < 0) currentIndex = events.length - 1;
46
+ const event = events[currentIndex];
47
+ const weekNum = getWeekNumberSinceBirth(event.date);
48
+ // Highlight the corresponding week in the grid
49
+ const weekDiv = document.querySelector('.week[data-week-number="' + (weekNum - 1) + '"]');
50
+ if (weekDiv) {
51
+ weekDiv.classList.add('carousel-pulse');
52
+ }
53
+ let main = '';
54
+ if (event.name && event.desc) {
55
+ main = `<span class="carousel-weeknum">Week ${weekNum}</span>: ${event.name}`;
56
+ quote.innerHTML = main;
57
+ meta.textContent = event.desc;
58
+ } else if (event.name) {
59
+ main = `<span class="carousel-weeknum">Week ${weekNum}</span>: ${event.name}`;
60
+ quote.innerHTML = main;
61
+ meta.textContent = '';
62
+ } else if (event.desc) {
63
+ main = `<span class="carousel-weeknum">Week ${weekNum}</span>`;
64
+ quote.innerHTML = main;
65
+ meta.textContent = event.desc;
66
+ } else {
67
+ quote.innerHTML = `<span class="carousel-weeknum">Week ${weekNum}</span>`;
68
+ meta.textContent = '';
69
+ }
70
+ }
71
+ window.updateLifeCarousel = updateCarousel;
72
+
73
+ function setupCarousel() {
74
+ loadEventsFromJson();
75
+ document.getElementById('life-carousel-up').addEventListener('click', function() {
76
+ const events = window.lifeInWeeksEvents || [];
77
+ currentIndex = (currentIndex - 1 + events.length) % events.length;
78
+ updateCarousel();
79
+ });
80
+ document.getElementById('life-carousel-down').addEventListener('click', function() {
81
+ const events = window.lifeInWeeksEvents || [];
82
+ currentIndex = (currentIndex + 1) % events.length;
83
+ updateCarousel();
84
+ });
85
+ updateCarousel();
86
+ }
87
+
88
+ if (document.readyState === 'loading') {
89
+ document.addEventListener('DOMContentLoaded', setupCarousel);
90
+ } else {
91
+ setupCarousel();
92
+ }
93
+ })();
data/assets/style.css CHANGED
@@ -1,7 +1,64 @@
1
+ /* Highlighted week number in carousel quote */
2
+ .carousel-weeknum {
3
+ color: var(--link-color);
4
+ font-weight: bold;
5
+ font-style: normal;
6
+ }
7
+ /* Pulse effect for carousel-selected week */
8
+ .carousel-pulse {
9
+ animation: carousel-pulse 1.2s cubic-bezier(0.4,0,0.6,1) infinite;
10
+ border-width: 2px !important;
11
+ border-color: var(--link-color) !important;
12
+ box-shadow: 0 0 10px rgba(124, 64, 17, 0.5);
13
+ z-index: 2;
14
+ }
15
+
16
+ @keyframes carousel-pulse {
17
+ 0% {
18
+ transform: scale(1);
19
+ opacity: 1;
20
+ }
21
+ 50% {
22
+ transform: scale(1.18);
23
+ opacity: 0.7;
24
+ }
25
+ 100% {
26
+ transform: scale(1);
27
+ opacity: 1;
28
+ }
29
+ }
30
+ /* Carousel arrow button styles */
31
+ #life-carousel-up, #life-carousel-down {
32
+ background: none;
33
+ border: none;
34
+ cursor: pointer;
35
+ font-size: 1.5em;
36
+ line-height: 1;
37
+ padding: 0.2em;
38
+ color: var(--main-color);
39
+ outline: none;
40
+ user-select: none;
41
+ -webkit-tap-highlight-color: transparent;
42
+ transition: color 0.2s;
43
+ }
44
+ #life-carousel-up:focus, #life-carousel-down:focus, #life-carousel-up:active, #life-carousel-down:active {
45
+ outline: none;
46
+ box-shadow: none;
47
+ background: none;
48
+ color: var(--main-color);
49
+ }
50
+ #life-carousel-up span, #life-carousel-down span {
51
+ color: inherit;
52
+ }
1
53
  /* Tooltip for event squares */
54
+
2
55
  .week[data-event] {
3
56
  position: relative;
4
- cursor: pointer;
57
+ cursor: default !important;
58
+ }
59
+
60
+ .week {
61
+ cursor: default !important;
5
62
  }
6
63
 
7
64
  /* Desktop: show tooltip on hover */
@@ -332,28 +389,11 @@ input[type=button], input[type=submit], input[type=reset] {
332
389
  align-items: flex-start;
333
390
  }
334
391
 
335
- /* Make weeks grid wider on larger screens while maintaining padding */
336
- @media (min-width: 1200px) {
337
- .weeks-grid {
338
- max-width: calc(100vw - 20vw);
339
- width: calc(100vw - 20vw);
340
- margin-left: calc((var(--width) - 100vw + 20vw) / 2);
341
- margin-right: calc((var(--width) - 100vw + 20vw) / 2);
342
- }
343
- }
344
-
345
- @media (min-width: 1400px) {
346
- .weeks-grid {
347
- max-width: calc(100vw - 20vw);
348
- width: calc(100vw - 20vw);
349
- margin-left: calc((var(--width) - 100vw + 20vw) / 2);
350
- margin-right: calc((var(--width) - 100vw + 20vw) / 2);
351
- }
352
- }
392
+ /* Removed wide-screen overrides for .weeks-grid to always fit its container */
353
393
 
354
394
  .week {
355
- min-width: 30px;
356
- height: 30px;
395
+ width: 16px;
396
+ height: 16px;
357
397
  border: 1px solid var(--main-color);
358
398
  background-color: var(--background-color);
359
399
  display: inline-flex;
@@ -364,7 +404,7 @@ input[type=button], input[type=submit], input[type=reset] {
364
404
  font-family: var(--font-thin);
365
405
  font-size: var(--font-scale);
366
406
  line-height: 1.5;
367
- padding: 4px 8px;
407
+ padding: 2px 2px;
368
408
  white-space: nowrap;
369
409
  box-sizing: border-box;
370
410
  }
@@ -391,11 +431,10 @@ input[type=button], input[type=submit], input[type=reset] {
391
431
 
392
432
  .week.has-events {
393
433
  border-color: var(--visited-color);
394
- color: var(--text-color);
434
+ background-color: var(--blockquote-color);
435
+ color: inherit;
395
436
  font-size: var(--font-scale);
396
- min-width: auto;
397
- width: auto;
398
- padding: 4px 10px;
437
+ padding: 0;
399
438
  }
400
439
 
401
440
  .week.has-events.future {
@@ -497,17 +536,40 @@ input[type=button], input[type=submit], input[type=reset] {
497
536
  }
498
537
 
499
538
  /* Responsive adjustments */
539
+ /* Responsive sizing to fit ~52 squares across screen width */
540
+ @media (max-width: 1200px) {
541
+ .week {
542
+ width: calc((100vw - 40px - (51 * 2px)) / 52);
543
+ height: calc((100vw - 40px - (51 * 2px)) / 52);
544
+ font-size: calc(var(--font-scale) * 0.8);
545
+ padding: 0;
546
+ min-width: 8px;
547
+ min-height: 8px;
548
+ }
549
+
550
+ .week.has-events {
551
+ font-size: calc(var(--font-scale) * 0.8);
552
+ padding: 0;
553
+ }
554
+ }
555
+
500
556
  @media (max-width: 768px) {
501
557
  .week {
502
- min-width: 26px;
503
- height: 26px;
504
- font-size: var(--font-scale);
505
- padding: 3px 7px;
558
+ width: calc((100vw - 40px - (51 * 1px)) / 52);
559
+ height: calc((100vw - 40px - (51 * 1px)) / 52);
560
+ font-size: calc(var(--font-scale) * 0.7);
561
+ padding: 0;
562
+ min-width: 8px;
563
+ min-height: 8px;
506
564
  }
507
565
 
508
566
  .week.has-events {
509
- font-size: var(--font-scale);
510
- padding: 3px 8px;
567
+ font-size: calc(var(--font-scale) * 0.7);
568
+ padding: 0;
569
+ }
570
+
571
+ .weeks-grid {
572
+ gap: 1px;
511
573
  }
512
574
 
513
575
  .event-desc {
@@ -517,15 +579,17 @@ input[type=button], input[type=submit], input[type=reset] {
517
579
 
518
580
  @media (max-width: 480px) {
519
581
  .week {
520
- min-width: 22px;
521
- height: 22px;
522
- font-size: var(--font-scale);
523
- padding: 2px 6px;
582
+ width: calc((100vw - 40px - (51 * 1px)) / 52);
583
+ height: calc((100vw - 40px - (51 * 1px)) / 52);
584
+ font-size: calc(var(--font-scale) * 0.6);
585
+ padding: 0;
586
+ min-width: 8px;
587
+ min-height: 8px;
524
588
  }
525
589
 
526
590
  .week.has-events {
527
- font-size: var(--font-scale);
528
- padding: 2px 7px;
591
+ font-size: calc(var(--font-scale) * 0.6);
592
+ padding: 0;
529
593
  }
530
594
 
531
595
  .weeks-grid {
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-bear-theme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - knhash
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-07-17 00:00:00.000000000 Z
10
+ date: 2025-07-18 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: jekyll
@@ -107,6 +107,7 @@ files:
107
107
  - assets/images/circle-about-tr.png
108
108
  - assets/images/circle-about.ico
109
109
  - assets/images/circle-about.png
110
+ - assets/life-carousel.js
110
111
  - assets/style.css
111
112
  homepage: https://knhash.in/jekyllBear
112
113
  licenses: