atlasdocs-theme 0.2.0__tar.gz → 0.2.1__tar.gz

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 (86) hide show
  1. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/PKG-INFO +1 -1
  2. atlasdocs_theme-0.2.1/atlasdocs_theme/assets/javascripts/indico_category_loader.js +188 -0
  3. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/pyproject.toml +1 -1
  4. atlasdocs_theme-0.2.0/atlasdocs_theme/assets/javascripts/indico_category_loader.js +0 -179
  5. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/.gitignore +0 -0
  6. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/404.html +0 -0
  7. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/AQP.html +0 -0
  8. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/JIRA.html +0 -0
  9. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/__init__.py +0 -0
  10. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/banners/network.jpg +0 -0
  11. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/fonts/OpenSans-Italic-VariableFont_wdth_wght.ttf +0 -0
  12. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/fonts/OpenSans-VariableFont_wdth_wght.ttf +0 -0
  13. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/fonts/RobotoMono-Italic-VariableFont_wght.ttf +0 -0
  14. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/fonts/RobotoMono-VariableFont_wght.ttf +0 -0
  15. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/images/logo.svg +0 -0
  16. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/athena_changelog_loader.js +0 -0
  17. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/extra.js +0 -0
  18. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/jira_project_loader.js +0 -0
  19. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/mathjax.js +0 -0
  20. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/tex.js +0 -0
  21. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff +0 -0
  22. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff +0 -0
  23. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff +0 -0
  24. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff +0 -0
  25. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff +0 -0
  26. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff +0 -0
  27. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff +0 -0
  28. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff +0 -0
  29. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff +0 -0
  30. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff +0 -0
  31. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Math-Regular.woff +0 -0
  32. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff +0 -0
  33. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff +0 -0
  34. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff +0 -0
  35. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff +0 -0
  36. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff +0 -0
  37. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff +0 -0
  38. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff +0 -0
  39. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff +0 -0
  40. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff +0 -0
  41. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff +0 -0
  42. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff +0 -0
  43. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/output/chtml/fonts/woff-v2/MathJax_Zero.woff +0 -0
  44. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/javascripts/twikiregistry.js +0 -0
  45. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/blocker.svg +0 -0
  46. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/critical.svg +0 -0
  47. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/high.svg +0 -0
  48. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/highest.svg +0 -0
  49. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/icons.jpg +0 -0
  50. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/low.svg +0 -0
  51. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/lowest.svg +0 -0
  52. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/major.svg +0 -0
  53. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/medium.svg +0 -0
  54. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/minor.svg +0 -0
  55. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/jira/trivial.svg +0 -0
  56. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/logo/atlaslogo.svg +0 -0
  57. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/stylesheets/badges.css +0 -0
  58. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/stylesheets/extra.classic.css +0 -0
  59. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/stylesheets/extra.css +0 -0
  60. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/stylesheets/jira.css +0 -0
  61. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/assets/stylesheets/twikiregistry.css +0 -0
  62. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/bookmarks.html +0 -0
  63. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/config/02-assets.toml +0 -0
  64. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/config/04-theme.toml +0 -0
  65. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/config/05-markdown.toml +0 -0
  66. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/config/06-plugins.toml +0 -0
  67. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/feedback.html +0 -0
  68. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/frontpage.html +0 -0
  69. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/main.html +0 -0
  70. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/mkdocs_theme.yml +0 -0
  71. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/actions.html +0 -0
  72. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/announce.html +0 -0
  73. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/aqp.html +0 -0
  74. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/atlas_authors.html +0 -0
  75. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/atlas_pagestatus.html +0 -0
  76. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/content.html +0 -0
  77. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/jira.html +0 -0
  78. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/page-actions.html +0 -0
  79. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/path-item.html +0 -0
  80. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/path.html +0 -0
  81. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/social.html +0 -0
  82. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/partials/source.html +0 -0
  83. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/atlasdocs_theme/user_profile.html +0 -0
  84. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/scripts/release.sh +0 -0
  85. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/scripts/test_css.py +0 -0
  86. {atlasdocs_theme-0.2.0 → atlasdocs_theme-0.2.1}/scripts/test_templates.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atlasdocs-theme
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: ATLASDocs hub theme for Zensical/MkDocs
5
5
  Author-email: Jason Oliver <jason.oliver@cern.ch>
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Lazy-loads a category_XXXX.json and renders meeting admonitions inline.
3
+ *
4
+ * Usage in a .md file body:
5
+ *
6
+ * <div id="indico-meetings" data-json="./category_XXXX.json"></div>
7
+ * <script src="path/to/indico_category_loader.js"></script>
8
+ *
9
+ * Or inline the script directly after the div.
10
+ * The div is populated once it scrolls into view (IntersectionObserver).
11
+ */
12
+ (function () {
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Lucide SVG icon strings (inline — no external dependency)
16
+ // ---------------------------------------------------------------------------
17
+
18
+ const ICONS = {
19
+ calendar: `<svg class="lucide lucide-calendar-days" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M8 2v4M16 2v4"/><rect height="18" rx="2" width="18" x="3" y="4"/><path d="M3 10h18M8 14h.01M12 14h.01M16 14h.01M8 18h.01M12 18h.01M16 18h.01"/></svg>`,
20
+ clock: `<svg class="lucide lucide-clock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>`,
21
+ mapPin: `<svg class="lucide lucide-map-pin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg>`,
22
+ notes: `<svg class="lucide lucide-notebook-pen" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4M2 6h4M2 10h4M2 14h4M2 18h4"/><path d="M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z"/></svg>`,
23
+ link: `<svg class="lucide lucide-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`,
24
+ users: `<svg class="lucide lucide-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M16 3.128a4 4 0 0 1 0 7.744M22 21v-2a4 4 0 0 0-3-3.87"/><circle cx="9" cy="7" r="4"/></svg>`,
25
+ file: `<svg class="lucide lucide-file-text" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5M10 9H8M16 13H8M16 17H8"/></svg>`,
26
+ };
27
+
28
+ function ic(key) {
29
+ return `<span class="twemoji">${ICONS[key]}</span>`;
30
+ }
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Formatting helpers
34
+ // ---------------------------------------------------------------------------
35
+
36
+ const MONTHS = [
37
+ 'January', 'February', 'March', 'April', 'May', 'June',
38
+ 'July', 'August', 'September', 'October', 'November', 'December'
39
+ ];
40
+
41
+ function ordinalSup(n) {
42
+ const v = n % 100;
43
+ const suffix = (v >= 11 && v <= 13) ? 'th'
44
+ : ['th', 'st', 'nd', 'rd'][n % 10] || 'th';
45
+ return `${n}<sup>${suffix}</sup>`;
46
+ }
47
+
48
+ function formatDate(dateStr) {
49
+ const [y, m, d] = dateStr.split('-').map(Number);
50
+ return `${MONTHS[m - 1]} ${ordinalSup(d)} ${y}`;
51
+ }
52
+
53
+ // start_time format in JSON: "1900-01-01 HH:MM:SS+00:00" (dummy date, real time)
54
+ function extractTime(timeStr) {
55
+ if (!timeStr) return null;
56
+ const m = timeStr.match(/\s(\d{2}:\d{2}):\d{2}/);
57
+ return m ? m[1] : null;
58
+ }
59
+
60
+ function meetingTimeRange(contributions) {
61
+ const times = contributions
62
+ .map(c => extractTime(c.start_time))
63
+ .filter(Boolean)
64
+ .sort();
65
+ if (!times.length) return null;
66
+ return times.length > 1 ? `${times[0]}–${times[times.length - 1]}` : times[0];
67
+ }
68
+
69
+ function humanSize(bytes) {
70
+ if (!bytes || bytes <= 0) return '';
71
+ const units = ['B', 'kB', 'MB', 'GB'];
72
+ let i = 0;
73
+ while (bytes >= 1024 && i < units.length - 1) { bytes /= 1024; i++; }
74
+ return `(${bytes.toFixed(1)}${units[i]})`;
75
+ }
76
+
77
+ // ---------------------------------------------------------------------------
78
+ // Renderers
79
+ // ---------------------------------------------------------------------------
80
+
81
+ function renderAttachment(att) {
82
+ const url = att.download_url || att.url || '';
83
+ const title = att.title || att.filename || 'attachment';
84
+ const size = humanSize(att.size);
85
+ return `<li>${ic('file')} <a href="${url}">${title}</a>`
86
+ + (size ? ` <span style="color:#777777">${size}</span>` : '')
87
+ + `</li>`;
88
+ }
89
+
90
+ function formatSpeakers(raw) {
91
+ if (!raw) return '';
92
+ if (typeof raw === 'string') return raw;
93
+ return raw.map(s => {
94
+ const name = s.fullName || [s.first_name, s.last_name].filter(Boolean).join(' ');
95
+ return s.affiliation ? `${name} (${s.affiliation})` : name;
96
+ }).filter(Boolean).join(', ');
97
+ }
98
+
99
+ function renderContribution(contrib) {
100
+ const speakers = formatSpeakers(contrib.speakers);
101
+ const minutesUrl = contrib.minutes?.url || '';
102
+ const atts = (contrib.attachments || []).map(renderAttachment).join('');
103
+
104
+ let line = `<a href="${contrib.url}">${contrib.title}</a>`;
105
+ if (speakers) line += ` | <strong>${ic('users')}</strong> ${speakers}`;
106
+ if (minutesUrl) line += ` <a href="${minutesUrl}">Minutes</a>`;
107
+
108
+ return `<li><p>${line}</p>${atts ? `<ul>${atts}</ul>` : ''}</li>`;
109
+ }
110
+
111
+ function renderMeeting(ev) {
112
+ const time = meetingTimeRange(ev.contributions || []);
113
+ const room = ev.room || ev.location || '';
114
+ const minutesUrl = ev.minutes_url || '';
115
+
116
+ const meta = [
117
+ `<strong>${ic('calendar')} Date:</strong> ${formatDate(ev.date)}`,
118
+ ];
119
+ if (time) meta.push(`<strong>${ic('clock')} Time:</strong> ${time}`);
120
+ if (room) meta.push(`<strong>${ic('mapPin')} Room:</strong> ${room}`);
121
+ if (minutesUrl) meta.push(`<strong>${ic('notes')} <a href="${minutesUrl}">Minutes</a></strong>`);
122
+ meta.push(`<strong>${ic('link')} <a href="${ev.url}">Event</a></strong>`);
123
+
124
+ const contribsHtml = (ev.contributions || []).map(renderContribution).join('');
125
+
126
+ return `<div class="admonition quote">`
127
+ + `<p class="admonition-title"><a href="${ev.url}">${ev.title}</a></p>`
128
+ + `<p>${meta.join(' | ')}</p>`
129
+ + (contribsHtml ? `<hr><ul>${contribsHtml}</ul>` : '')
130
+ + `</div>`;
131
+ }
132
+
133
+ function renderAll(container, events) {
134
+ const filtered = events.filter(ev => ev._type !== 'category_metadata' && ev.date);
135
+
136
+ // Group by month, newest first
137
+ const byMonth = new Map();
138
+ filtered
139
+ .sort((a, b) => b.date.localeCompare(a.date))
140
+ .forEach(ev => {
141
+ const [y, m] = ev.date.split('-').map(Number);
142
+ const key = `${y}-${String(m).padStart(2, '0')}`;
143
+ const label = `${MONTHS[m - 1]} ${y}`;
144
+ if (!byMonth.has(key)) byMonth.set(key, { label, events: [] });
145
+ byMonth.get(key).events.push(ev);
146
+ });
147
+
148
+ const html = [...byMonth.entries()]
149
+ .sort(([a], [b]) => b.localeCompare(a))
150
+ .map(([, { label, events: evs }]) =>
151
+ `<h2>${label}</h2>\n` + evs.map(renderMeeting).join('\n')
152
+ )
153
+ .join('\n');
154
+
155
+ container.innerHTML = html || '<p><em>No meetings found.</em></p>';
156
+ }
157
+
158
+ // ---------------------------------------------------------------------------
159
+ // Fetch + lazy-load trigger
160
+ // ---------------------------------------------------------------------------
161
+
162
+ function load(container) {
163
+ const src = container.dataset.json;
164
+ if (!src) return;
165
+ container.innerHTML = '<p><em>Loading…</em></p>';
166
+ fetch(src)
167
+ .then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); })
168
+ .then(data => renderAll(container, Array.isArray(data) ? data : (data.events || [])))
169
+ .catch(err => {
170
+ container.innerHTML = `<p><em>Could not load meetings: ${err.message}</em></p>`;
171
+ });
172
+ }
173
+
174
+ const container = document.getElementById('indico-meetings');
175
+ if (!container) return;
176
+
177
+ // Pre-load 300 px before the div enters the viewport
178
+ const observer = new IntersectionObserver(
179
+ (entries, obs) => {
180
+ entries.forEach(entry => {
181
+ if (entry.isIntersecting) { obs.unobserve(entry.target); load(entry.target); }
182
+ });
183
+ },
184
+ { rootMargin: '300px' }
185
+ );
186
+
187
+ observer.observe(container);
188
+ })();
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "atlasdocs-theme"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "ATLASDocs hub theme for Zensical/MkDocs"
9
9
  authors = [
10
10
  { name = "Jason Oliver", email = "jason.oliver@cern.ch" }
@@ -1,179 +0,0 @@
1
- /**
2
- * Lazy-loads a category_XXXX.json and renders meeting admonitions inline.
3
- *
4
- * Usage in a .md file body:
5
- *
6
- * <div id="indico-meetings" data-json="./category_XXXX.json"></div>
7
- * <script src="path/to/indico_category_loader.js"></script>
8
- *
9
- * Or inline the script directly after the div.
10
- * The div is populated once it scrolls into view (IntersectionObserver).
11
- */
12
- (function () {
13
-
14
- // ---------------------------------------------------------------------------
15
- // Lucide SVG icon strings (inline — no external dependency)
16
- // ---------------------------------------------------------------------------
17
-
18
- const ICONS = {
19
- calendar: `<svg class="lucide lucide-calendar-days" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M8 2v4M16 2v4"/><rect height="18" rx="2" width="18" x="3" y="4"/><path d="M3 10h18M8 14h.01M12 14h.01M16 14h.01M8 18h.01M12 18h.01M16 18h.01"/></svg>`,
20
- clock: `<svg class="lucide lucide-clock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>`,
21
- mapPin: `<svg class="lucide lucide-map-pin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg>`,
22
- notes: `<svg class="lucide lucide-notebook-pen" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4M2 6h4M2 10h4M2 14h4M2 18h4"/><path d="M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z"/></svg>`,
23
- link: `<svg class="lucide lucide-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`,
24
- users: `<svg class="lucide lucide-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M16 3.128a4 4 0 0 1 0 7.744M22 21v-2a4 4 0 0 0-3-3.87"/><circle cx="9" cy="7" r="4"/></svg>`,
25
- file: `<svg class="lucide lucide-file-text" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" xmlns="http://www.w3.org/2000/svg"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5M10 9H8M16 13H8M16 17H8"/></svg>`,
26
- };
27
-
28
- function ic(key) {
29
- return `<span class="twemoji">${ICONS[key]}</span>`;
30
- }
31
-
32
- // ---------------------------------------------------------------------------
33
- // Formatting helpers
34
- // ---------------------------------------------------------------------------
35
-
36
- const MONTHS = [
37
- 'January','February','March','April','May','June',
38
- 'July','August','September','October','November','December'
39
- ];
40
-
41
- function ordinalSup(n) {
42
- const v = n % 100;
43
- const suffix = (v >= 11 && v <= 13) ? 'th'
44
- : ['th','st','nd','rd'][n % 10] || 'th';
45
- return `${n}<sup>${suffix}</sup>`;
46
- }
47
-
48
- function formatDate(dateStr) {
49
- const [y, m, d] = dateStr.split('-').map(Number);
50
- return `${MONTHS[m - 1]} ${ordinalSup(d)} ${y}`;
51
- }
52
-
53
- // start_time format in JSON: "1900-01-01 HH:MM:SS+00:00" (dummy date, real time)
54
- function extractTime(timeStr) {
55
- if (!timeStr) return null;
56
- const m = timeStr.match(/\s(\d{2}:\d{2}):\d{2}/);
57
- return m ? m[1] : null;
58
- }
59
-
60
- function meetingTimeRange(contributions) {
61
- const times = contributions
62
- .map(c => extractTime(c.start_time))
63
- .filter(Boolean)
64
- .sort();
65
- if (!times.length) return null;
66
- return times.length > 1 ? `${times[0]}–${times[times.length - 1]}` : times[0];
67
- }
68
-
69
- function humanSize(bytes) {
70
- if (!bytes || bytes <= 0) return '';
71
- const units = ['B', 'kB', 'MB', 'GB'];
72
- let i = 0;
73
- while (bytes >= 1024 && i < units.length - 1) { bytes /= 1024; i++; }
74
- return `(${bytes.toFixed(1)}${units[i]})`;
75
- }
76
-
77
- // ---------------------------------------------------------------------------
78
- // Renderers
79
- // ---------------------------------------------------------------------------
80
-
81
- function renderAttachment(att) {
82
- const url = att.download_url || att.url || '';
83
- const title = att.title || att.filename || 'attachment';
84
- const size = humanSize(att.size);
85
- return `<li>${ic('file')} <a href="${url}">${title}</a>`
86
- + (size ? ` <span style="color:#777777">${size}</span>` : '')
87
- + `</li>`;
88
- }
89
-
90
- function renderContribution(contrib) {
91
- const speakers = contrib.speakers || '';
92
- const minutesUrl = contrib.minutes?.url || '';
93
- const atts = (contrib.attachments || []).map(renderAttachment).join('');
94
-
95
- let line = `<a href="${contrib.url}">${contrib.title}</a>`;
96
- if (speakers) line += ` | <strong>${ic('users')}</strong> ${speakers}`;
97
- if (minutesUrl) line += ` <a href="${minutesUrl}">Minutes</a>`;
98
-
99
- return `<li><p>${line}</p>${atts ? `<ul>${atts}</ul>` : ''}</li>`;
100
- }
101
-
102
- function renderMeeting(ev) {
103
- const time = meetingTimeRange(ev.contributions || []);
104
- const room = ev.room || ev.location || '';
105
- const minutesUrl = ev.minutes_url || '';
106
-
107
- const meta = [
108
- `<strong>${ic('calendar')} Date:</strong> ${formatDate(ev.date)}`,
109
- ];
110
- if (time) meta.push(`<strong>${ic('clock')} Time:</strong> ${time}`);
111
- if (room) meta.push(`<strong>${ic('mapPin')} Room:</strong> ${room}`);
112
- if (minutesUrl) meta.push(`<strong>${ic('notes')} <a href="${minutesUrl}">Minutes</a></strong>`);
113
- meta.push(`<strong>${ic('link')} <a href="${ev.url}">Event</a></strong>`);
114
-
115
- const contribsHtml = (ev.contributions || []).map(renderContribution).join('');
116
-
117
- return `<div class="admonition quote">`
118
- + `<p class="admonition-title"><a href="${ev.url}">${ev.title}</a></p>`
119
- + `<p>${meta.join(' | ')}</p>`
120
- + (contribsHtml ? `<hr><ul>${contribsHtml}</ul>` : '')
121
- + `</div>`;
122
- }
123
-
124
- function renderAll(container, events) {
125
- const filtered = events.filter(ev => ev._type !== 'category_metadata' && ev.date);
126
-
127
- // Group by month, newest first
128
- const byMonth = new Map();
129
- filtered
130
- .sort((a, b) => b.date.localeCompare(a.date))
131
- .forEach(ev => {
132
- const [y, m] = ev.date.split('-').map(Number);
133
- const key = `${y}-${String(m).padStart(2, '0')}`;
134
- const label = `${MONTHS[m - 1]} ${y}`;
135
- if (!byMonth.has(key)) byMonth.set(key, { label, events: [] });
136
- byMonth.get(key).events.push(ev);
137
- });
138
-
139
- const html = [...byMonth.entries()]
140
- .sort(([a], [b]) => b.localeCompare(a))
141
- .map(([, { label, events: evs }]) =>
142
- `<h2>${label}</h2>\n` + evs.map(renderMeeting).join('\n')
143
- )
144
- .join('\n');
145
-
146
- container.innerHTML = html || '<p><em>No meetings found.</em></p>';
147
- }
148
-
149
- // ---------------------------------------------------------------------------
150
- // Fetch + lazy-load trigger
151
- // ---------------------------------------------------------------------------
152
-
153
- function load(container) {
154
- const src = container.dataset.json;
155
- if (!src) return;
156
- container.innerHTML = '<p><em>Loading…</em></p>';
157
- fetch(src)
158
- .then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); })
159
- .then(data => renderAll(container, Array.isArray(data) ? data : (data.events || [])))
160
- .catch(err => {
161
- container.innerHTML = `<p><em>Could not load meetings: ${err.message}</em></p>`;
162
- });
163
- }
164
-
165
- const container = document.getElementById('indico-meetings');
166
- if (!container) return;
167
-
168
- // Pre-load 300 px before the div enters the viewport
169
- const observer = new IntersectionObserver(
170
- (entries, obs) => {
171
- entries.forEach(entry => {
172
- if (entry.isIntersecting) { obs.unobserve(entry.target); load(entry.target); }
173
- });
174
- },
175
- { rootMargin: '300px' }
176
- );
177
-
178
- observer.observe(container);
179
- })();