calconnect-theme 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0e824002c5711ee52976d652137fa80928e296b19dc39afbb9ac1655da482251
4
+ data.tar.gz: 175bc2566a39e161036d86fea1381ed7024c73c026ca5f7806e0d4bf65e68f86
5
+ SHA512:
6
+ metadata.gz: 042c810a73ea40e70481c8378e4da97c13e67b1f105c7c1fe43fb42edd214ca82c2fbf9335eef1f1a49143507724ecae8c947892f5537a95f3403a3868ed3099
7
+ data.tar.gz: 94216bd40ade3ab5bd2d3fc752444b35874fded4faec6a6804e6dde55d36333f4044310a0d125e1b9b62b85a1b556d73b485d2b76740d8bc535b18a1264bfcef
data/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # calconnect-theme
2
+
3
+ Shared Jekyll theme gem for CalConnect sites (calconnect.org, DEVGUIDE, standards.calconnect.org).
4
+
5
+ ## Usage
6
+
7
+ Add to your site's `Gemfile`:
8
+
9
+ ```ruby
10
+ gem "calconnect-theme", git: "git@github.com:calconnect/calconnect-theme.git"
11
+ ```
12
+
13
+ Add to your site's `_config.yml`:
14
+
15
+ ```yaml
16
+ theme: calconnect-theme
17
+ ```
18
+
19
+ ## Site-specific overrides
20
+
21
+ Any layout or include can be overridden by placing a file with the same name in your site's own `_layouts/` or `_includes/` directory.
@@ -0,0 +1,80 @@
1
+ @import "tailwindcss";
2
+ @plugin "@tailwindcss/typography";
3
+
4
+ /* Enable class-based dark mode */
5
+ @custom-variant dark (&:where(.dark, .dark *));
6
+
7
+ /* Custom theme configuration */
8
+ @theme {
9
+ /* Font families */
10
+ --font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
11
+ --font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
12
+
13
+ /* Primary colors */
14
+ --color-primary-50: #eef2ff;
15
+ --color-primary-100: #e0e7ff;
16
+ --color-primary-200: #c7d2fe;
17
+ --color-primary-300: #a5b4fc;
18
+ --color-primary-400: #818cf8;
19
+ --color-primary-500: #6366f1;
20
+ --color-primary-600: #4f46e5;
21
+ --color-primary-700: #4338ca;
22
+ --color-primary-800: #3730a3;
23
+ --color-primary-900: #312e81;
24
+
25
+ /* Accent color */
26
+ --color-accent-400: #22d3ee;
27
+ --color-accent-500: #06b6d4;
28
+ }
29
+
30
+ /* Custom base styles */
31
+ @layer base {
32
+ html {
33
+ scroll-behavior: smooth;
34
+ }
35
+
36
+ body {
37
+ font-feature-settings: "kern" 1, "liga" 1;
38
+ -webkit-font-smoothing: antialiased;
39
+ -moz-osx-font-smoothing: grayscale;
40
+ }
41
+
42
+ main {
43
+ padding-top: 64px;
44
+ }
45
+
46
+ ::selection {
47
+ background-color: rgba(99, 102, 241, 0.2);
48
+ }
49
+
50
+ :focus-visible {
51
+ outline: 2px solid #6366f1;
52
+ outline-offset: 2px;
53
+ }
54
+ }
55
+
56
+ /* Custom component styles */
57
+ @layer components {
58
+ .sr-only {
59
+ position: absolute;
60
+ width: 1px;
61
+ height: 1px;
62
+ padding: 0;
63
+ margin: -1px;
64
+ overflow: hidden;
65
+ clip: rect(0, 0, 0, 0);
66
+ white-space: nowrap;
67
+ border-width: 0;
68
+ }
69
+
70
+ .sr-only:focus {
71
+ position: fixed;
72
+ width: auto;
73
+ height: auto;
74
+ padding: 0.5rem 1rem;
75
+ margin: 0;
76
+ overflow: visible;
77
+ clip: auto;
78
+ white-space: normal;
79
+ }
80
+ }
@@ -0,0 +1,12 @@
1
+ import '../js/theme.js'
2
+ import '../js/navigation.js'
3
+
4
+ document.addEventListener('DOMContentLoaded', function() {
5
+ document.querySelectorAll('.nav-toggle').forEach(function(toggle) {
6
+ toggle.addEventListener('click', function() {
7
+ this.classList.toggle('open');
8
+ var subsection = this.nextElementSibling;
9
+ if (subsection) subsection.classList.toggle('collapsed');
10
+ });
11
+ });
12
+ });
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Navigation Script
3
+ * Handles mobile menu toggle and active state highlighting
4
+ */
5
+
6
+ (function() {
7
+ 'use strict';
8
+
9
+ /**
10
+ * Initialize mobile menu toggle
11
+ */
12
+ function initMobileMenu() {
13
+ var menuButton = document.getElementById('mobile-menu-btn');
14
+ var mobileMenu = document.getElementById('mobile-menu');
15
+
16
+ if (menuButton && mobileMenu) {
17
+ menuButton.addEventListener('click', function() {
18
+ var isExpanded = menuButton.getAttribute('aria-expanded') === 'true';
19
+ menuButton.setAttribute('aria-expanded', !isExpanded);
20
+ mobileMenu.classList.toggle('hidden');
21
+ });
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Highlight active navigation items
27
+ */
28
+ function initActiveNav() {
29
+ var currentPath = window.location.pathname;
30
+
31
+ // Sidebar navigation
32
+ var sidebarLinks = document.querySelectorAll('.docs-nav .nav-items a');
33
+ sidebarLinks.forEach(function(link) {
34
+ var href = link.getAttribute('href');
35
+ if (href) {
36
+ // Normalize paths for comparison
37
+ var linkPath = href.replace(/\/$/, '');
38
+ var pagePath = currentPath.replace(/\/$/, '');
39
+ if (linkPath === pagePath) {
40
+ link.classList.add('active');
41
+ }
42
+ }
43
+ });
44
+
45
+ // Header navigation
46
+ var headerLinks = document.querySelectorAll('nav a[href]');
47
+ headerLinks.forEach(function(link) {
48
+ var href = link.getAttribute('href');
49
+ if (href && href !== '/') {
50
+ var linkPath = href.replace(/\/$/, '');
51
+ var pagePath = currentPath.replace(/\/$/, '');
52
+ if (pagePath.indexOf(linkPath) === 0) {
53
+ link.classList.add('active');
54
+ }
55
+ }
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Initialize on DOM ready
61
+ */
62
+ document.addEventListener('DOMContentLoaded', function() {
63
+ initMobileMenu();
64
+ initActiveNav();
65
+ });
66
+ })();
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Theme Toggle Script
3
+ * Handles dark/light mode switching with localStorage persistence
4
+ */
5
+
6
+ (function() {
7
+ 'use strict';
8
+
9
+ /**
10
+ * Get the user's theme preference
11
+ * Priority: localStorage > system preference
12
+ */
13
+ function getThemePreference() {
14
+ if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
15
+ return localStorage.getItem('theme');
16
+ }
17
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
18
+ }
19
+
20
+ /**
21
+ * Set the theme on the document
22
+ */
23
+ function setTheme(theme) {
24
+ if (theme === 'dark') {
25
+ document.documentElement.classList.add('dark');
26
+ } else {
27
+ document.documentElement.classList.remove('dark');
28
+ }
29
+ localStorage.setItem('theme', theme);
30
+ }
31
+
32
+ /**
33
+ * Initialize theme immediately to prevent flash
34
+ */
35
+ setTheme(getThemePreference());
36
+
37
+ /**
38
+ * Handle DOM ready for toggle button
39
+ */
40
+ document.addEventListener('DOMContentLoaded', function() {
41
+ var toggle = document.getElementById('theme-toggle');
42
+ if (toggle) {
43
+ toggle.addEventListener('click', function() {
44
+ var currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
45
+ setTheme(currentTheme === 'dark' ? 'light' : 'dark');
46
+ });
47
+ }
48
+ });
49
+
50
+ /**
51
+ * Handle system preference changes
52
+ */
53
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) {
54
+ if (!localStorage.getItem('theme')) {
55
+ setTheme(e.matches ? 'dark' : 'light');
56
+ }
57
+ });
58
+ })();
@@ -0,0 +1,23 @@
1
+ <nav class="hidden lg:flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 mb-4" aria-label="Breadcrumb">
2
+ <ol class="flex items-center flex-wrap gap-2 list-none p-0 m-0">
3
+ <li><a href="{{ '/' | relative_url }}" class="hover:text-gray-700 dark:hover:text-gray-300">Home</a></li>
4
+ {% assign crumbs = page.url | remove:'/index.html' | split: '/' %}
5
+ {% if page.collection == 'posts' %}
6
+ <li>/ <a href="{{ '/news' | relative_url }}" class="hover:text-gray-700 dark:hover:text-gray-300">News</a></li>
7
+ <li>/ {{ page.title }}</li>
8
+ {% else %}
9
+ {% for crumb in crumbs offset: 1 %}
10
+ {% if forloop.last %}
11
+ <li>/ {{ page.title }}</li>
12
+ {% else %}
13
+ {% assign crumb_limit = forloop.index | plus: 1 %}
14
+ {% assign crumb_url = '' %}
15
+ {% for crumb in crumbs limit: crumb_limit %}
16
+ {% assign crumb_url = crumb_url | append: crumb | append: '/' %}
17
+ {% endfor %}
18
+ <li>/ <a href="{{ crumb_url | absolute_url }}" class="hover:text-gray-700 dark:hover:text-gray-300">{{ crumb | replace: '-', ' ' | capitalize }}</a></li>
19
+ {% endif %}
20
+ {% endfor %}
21
+ {% endif %}
22
+ </ol>
23
+ </nav>
@@ -0,0 +1,2 @@
1
+ {% vite_client_tag %}
2
+ {% vite_javascript_tag application %}
@@ -0,0 +1,3 @@
1
+ <div class="border-t border-gray-200 dark:border-gray-700 mt-8 pt-6">
2
+ <p class="text-sm text-gray-500 dark:text-gray-400">Was this page helpful? Please give us <a href="https://goo.gl/forms/NqKna6d4lsqUtlgD3" class="text-indigo-500 hover:text-indigo-600 underline" target="_blank" rel="noopener">Feedback</a>.</p>
3
+ </div>
@@ -0,0 +1,10 @@
1
+ <footer class="bg-gray-50 dark:bg-gray-950 border-t border-gray-200 dark:border-white/10 py-12 transition-colors">
2
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
3
+ <div class="pt-8 border-t border-gray-200 dark:border-white/10">
4
+ <p class="text-sm text-gray-500 dark:text-gray-400">
5
+ &copy; {{ site.time | date: '%Y' }} CalConnect<sup>SM</sup>.
6
+ <a href="https://www.calconnect.org/about/policies/copyright-and-licensing" class="hover:text-gray-700 dark:hover:text-gray-300">Copyright</a>
7
+ </p>
8
+ </div>
9
+ </div>
10
+ </footer>
@@ -0,0 +1,9 @@
1
+ <script>
2
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
3
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
4
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
5
+ })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
6
+
7
+ ga('create', '{{ site.google_analytics }}', 'auto');
8
+ ga('send', 'pageview');
9
+ </script>
@@ -0,0 +1,33 @@
1
+ <head>
2
+ <meta charset="UTF-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4
+ {% assign page_title = page.title | default: page.name %}
5
+ <title>{% if page_title %}{{ page_title | escape }} | {% endif %}{{ site.title | default: "CalConnect" }}</title>
6
+ <meta name="description"
7
+ content="{{ page.excerpt | default: site.description | strip_html | normalize_whitespace | truncate: 160 | escape }}" />
8
+
9
+ {% if site.favicon %}
10
+ <link rel="icon" type="image/png" href="{{ site.favicon | relative_url }}" sizes="96x96" />
11
+ {% endif %}
12
+
13
+ <!-- Google Fonts - Inter + JetBrains Mono -->
14
+ <link rel="preconnect" href="https://fonts.googleapis.com">
15
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
16
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
17
+
18
+ <!-- Critical CSS to prevent flash of unstyled content -->
19
+ <style>
20
+ html{scroll-behavior:smooth!important}
21
+ body{font-feature-settings:"kern" 1,"liga" 1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:#fff!important;color:#1e293b!important;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,sans-serif!important;opacity:1!important}
22
+ html.dark body{background-color:#0f172a!important;color:#f1f5f9!important}
23
+ #nav-header{position:fixed!important;top:0!important;left:0!important;right:0!important;z-index:50!important;height:64px!important}
24
+ main{padding-top:64px!important}
25
+ </style>
26
+
27
+ <!-- Vite Stylesheet (Tailwind CSS) -->
28
+ {% vite_stylesheet_tag application %}
29
+
30
+ {% if jekyll.environment == 'production' and site.google_analytics %}
31
+ {% include google-analytics.html %}
32
+ {% endif %}
33
+ </head>
@@ -0,0 +1,9 @@
1
+ <header id="nav-header" class="fixed top-0 left-0 right-0 z-50 bg-white dark:bg-gray-950 backdrop-blur-md border-b border-gray-200 dark:border-white/10 transition-colors">
2
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
3
+ <div class="flex items-center justify-between h-16">
4
+ <a href="{{ '/' | relative_url }}" class="flex items-center">
5
+ <span class="text-lg font-semibold text-gray-900 dark:text-white">{{ site.title | default: "CalConnect" }}</span>
6
+ </a>
7
+ </div>
8
+ </div>
9
+ </header>
@@ -0,0 +1,21 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="">
3
+
4
+ {% include head.html %}
5
+
6
+ <body class="bg-white dark:bg-gray-950 text-gray-900 dark:text-white">
7
+ <a href="#main-content" class="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:bg-indigo-500 focus:text-white focus:px-4 focus:py-2 focus:rounded-lg">
8
+ Skip to main content
9
+ </a>
10
+
11
+ {% include header.html %}
12
+
13
+ <main id="main-content">
14
+ {{ content }}
15
+ </main>
16
+
17
+ {% include footer.html %}
18
+
19
+ {% vite_javascript_tag application %}
20
+ </body>
21
+ </html>
@@ -0,0 +1,254 @@
1
+ ---
2
+ layout: base
3
+ ---
4
+
5
+ <section class="documentation">
6
+ <!-- Left Sidebar Navigation - Fully Data-Driven -->
7
+ <nav class="docs-nav" aria-label="Section navigation">
8
+ <div class="docs-nav-content">
9
+
10
+ {% comment %}
11
+ Find matching section based on page URL.
12
+ The layout has no knowledge of specific pages - all configuration is in _data/navigation_sidebar.yml
13
+ {% endcomment %}
14
+ {% assign current_section = nil %}
15
+ {% for section in site.data.navigation_sidebar.sections %}
16
+ {% if page.url contains section.match %}
17
+ {% assign current_section = section %}
18
+ {% break %}
19
+ {% endif %}
20
+ {% endfor %}
21
+
22
+ {% if current_section %}
23
+ <div class="nav-section">
24
+ <div class="nav-section-title">{{ current_section.title }}</div>
25
+ <ul class="nav-items">
26
+ {% for item in current_section.items %}
27
+
28
+ {% comment %} --- LINK TYPE --- {% endcomment %}
29
+ {% if item.type == 'link' or item.type == nil %}
30
+ {% assign is_active = false %}
31
+ {% if page.url == item.url %}
32
+ {% assign is_active = true %}
33
+ {% endif %}
34
+ <li>
35
+ <a href="{{ item.url | relative_url }}" {% if is_active %}class="active"{% endif %}>
36
+ {{ item.label }}
37
+ </a>
38
+ </li>
39
+
40
+ {% comment %} --- COLLECTION TYPE --- {% endcomment %}
41
+ {% elsif item.type == 'collection' %}
42
+ {% case item.collection %}
43
+ {% when 'about_pages' %}
44
+ {% assign docs = site.about_pages %}
45
+ {% when 'membership_pages' %}
46
+ {% assign docs = site.membership_pages %}
47
+ {% when 'events' %}
48
+ {% assign docs = site.events %}
49
+ {% when 'resources' %}
50
+ {% assign docs = site.resources %}
51
+ {% else %}
52
+ {% assign docs = site.posts %}
53
+ {% endcase %}
54
+ {% if item.sort_field == 'date' and item.sort_order == 'desc' %}
55
+ {% assign sorted_docs = docs | sort: 'date' | reverse %}
56
+ {% elsif item.sort_field %}
57
+ {% assign sorted_docs = docs | sort: item.sort_field %}
58
+ {% else %}
59
+ {% assign sorted_docs = docs %}
60
+ {% endif %}
61
+ {% for doc in sorted_docs %}
62
+ {% assign is_doc_active = false %}
63
+ {% if page.url == doc.url %}
64
+ {% assign is_doc_active = true %}
65
+ {% endif %}
66
+ <li>
67
+ <a href="{{ doc.url | relative_url }}" {% if is_doc_active %}class="active"{% endif %}>
68
+ {{ doc.title | default: doc.name }}
69
+ </a>
70
+ </li>
71
+ {% endfor %}
72
+
73
+ {% comment %} --- COLLAPSIBLE TYPE --- {% endcomment %}
74
+ {% elsif item.type == 'collapsible' %}
75
+ {% assign is_open = false %}
76
+ {% if page.url contains item.url_filter %}
77
+ {% assign is_open = true %}
78
+ {% endif %}
79
+ {% case item.collection %}
80
+ {% when 'about_pages' %}
81
+ {% assign child_docs = site.about_pages %}
82
+ {% when 'membership_pages' %}
83
+ {% assign child_docs = site.membership_pages %}
84
+ {% when 'events' %}
85
+ {% assign child_docs = site.events %}
86
+ {% when 'resources' %}
87
+ {% assign child_docs = site.resources %}
88
+ {% else %}
89
+ {% assign child_docs = site.posts %}
90
+ {% endcase %}
91
+ <li>
92
+ <span class="nav-toggle {% if is_open %}open{% endif %}">{{ item.label }}</span>
93
+ <ul class="nav-subsection {% unless is_open %}collapsed{% endunless %}">
94
+ {% if item.first_child_label %}
95
+ {% assign first_is_active = false %}
96
+ {% if page.url contains item.url_filter %}
97
+ {% assign first_is_active = true %}
98
+ {% endif %}
99
+ <li><a href="{{ item.url | relative_url }}" {% if first_is_active %}class="active"{% endif %}>{{ item.first_child_label }}</a></li>
100
+ {% endif %}
101
+ {% for doc in child_docs %}
102
+ {% assign url_matches = false %}
103
+ {% if doc.url contains item.url_filter %}
104
+ {% assign url_matches = true %}
105
+ {% endif %}
106
+ {% assign is_excluded = false %}
107
+ {% if doc.url == item.url %}
108
+ {% assign is_excluded = true %}
109
+ {% endif %}
110
+ {% if item.exclude_urls %}
111
+ {% for excl in item.exclude_urls %}
112
+ {% if doc.url == excl %}
113
+ {% assign is_excluded = true %}
114
+ {% endif %}
115
+ {% endfor %}
116
+ {% elsif item.exclude_url %}
117
+ {% if doc.url == item.exclude_url %}
118
+ {% assign is_excluded = true %}
119
+ {% endif %}
120
+ {% endif %}
121
+ {% if url_matches and is_excluded == false %}
122
+ {% assign child_is_active = false %}
123
+ {% if page.url == doc.url %}
124
+ {% assign child_is_active = true %}
125
+ {% endif %}
126
+ <li>
127
+ <a href="{{ doc.url | relative_url }}" {% if child_is_active %}class="active"{% endif %}>
128
+ {{ doc.title }}
129
+ </a>
130
+ </li>
131
+ {% endif %}
132
+ {% endfor %}
133
+ </ul>
134
+ </li>
135
+
136
+ {% comment %} --- YEARS TYPE --- {% endcomment %}
137
+ {% elsif item.type == 'years' %}
138
+ {% assign years = site.data.news_years %}
139
+ {% for year in years %}
140
+ {% assign is_active = false %}
141
+ {% if page.url contains year %}
142
+ {% assign is_active = true %}
143
+ {% endif %}
144
+ <li>
145
+ <a href="/news/{{ year }}/" {% if is_active %}class="active"{% endif %}>
146
+ {{ year }}
147
+ </a>
148
+ </li>
149
+ {% endfor %}
150
+
151
+ {% comment %} --- GROUP TYPE --- {% endcomment %}
152
+ {% elsif item.type == 'group' %}
153
+ </ul>
154
+ <div class="nav-group-title">{{ item.label }}</div>
155
+ <ul class="nav-items">
156
+ {% for child in item.children %}
157
+ {% if child.type == 'link' or child.type == nil %}
158
+ {% assign group_link_active = false %}
159
+ {% if page.url == child.url %}
160
+ {% assign group_link_active = true %}
161
+ {% endif %}
162
+ <li>
163
+ <a href="{{ child.url | relative_url }}" {% if group_link_active %}class="active"{% endif %}>
164
+ {{ child.label }}
165
+ </a>
166
+ </li>
167
+ {% elsif child.type == 'collapsible' %}
168
+ {% assign is_open = false %}
169
+ {% if page.url contains child.url_filter %}
170
+ {% assign is_open = true %}
171
+ {% endif %}
172
+ {% case child.collection %}
173
+ {% when 'about_pages' %}
174
+ {% assign child_docs = site.about_pages %}
175
+ {% when 'membership_pages' %}
176
+ {% assign child_docs = site.membership_pages %}
177
+ {% when 'events' %}
178
+ {% assign child_docs = site.events %}
179
+ {% when 'resources' %}
180
+ {% assign child_docs = site.resources %}
181
+ {% else %}
182
+ {% assign child_docs = site.posts %}
183
+ {% endcase %}
184
+ <li>
185
+ <span class="nav-toggle {% if is_open %}open{% endif %}">{{ child.label }}</span>
186
+ <ul class="nav-subsection {% unless is_open %}collapsed{% endunless %}">
187
+ {% if child.first_child_label %}
188
+ {% assign group_first_active = false %}
189
+ {% if page.url contains child.url_filter %}
190
+ {% assign group_first_active = true %}
191
+ {% endif %}
192
+ <li><a href="{{ child.url | relative_url }}" {% if group_first_active %}class="active"{% endif %}>{{ child.first_child_label }}</a></li>
193
+ {% endif %}
194
+ {% for doc in child_docs %}
195
+ {% assign url_matches = false %}
196
+ {% if doc.url contains child.url_filter %}
197
+ {% assign url_matches = true %}
198
+ {% endif %}
199
+ {% assign is_excluded = false %}
200
+ {% if doc.url == child.url %}
201
+ {% assign is_excluded = true %}
202
+ {% endif %}
203
+ {% if child.exclude_urls %}
204
+ {% for excl in child.exclude_urls %}
205
+ {% if doc.url == excl %}
206
+ {% assign is_excluded = true %}
207
+ {% endif %}
208
+ {% endfor %}
209
+ {% elsif child.exclude_url %}
210
+ {% if doc.url == child.exclude_url %}
211
+ {% assign is_excluded = true %}
212
+ {% endif %}
213
+ {% endif %}
214
+ {% if url_matches and is_excluded == false %}
215
+ {% assign group_doc_active = false %}
216
+ {% if page.url == doc.url %}
217
+ {% assign group_doc_active = true %}
218
+ {% endif %}
219
+ <li>
220
+ <a href="{{ doc.url | relative_url }}" {% if group_doc_active %}class="active"{% endif %}>
221
+ {{ doc.title }}
222
+ </a>
223
+ </li>
224
+ {% endif %}
225
+ {% endfor %}
226
+ </ul>
227
+ </li>
228
+ {% endif %}
229
+ {% endfor %}
230
+
231
+ {% endif %}
232
+
233
+ {% endfor %}
234
+ </ul>
235
+ </div>
236
+ {% endif %}
237
+
238
+ </div>
239
+ </nav>
240
+
241
+ <!-- Main Article -->
242
+ <article>
243
+ {% assign page_title = page.title | default: page.name %}
244
+ {% if page_title %}
245
+ <header>
246
+ <h1>{{ page_title }}</h1>
247
+ </header>
248
+ {% endif %}
249
+
250
+ <div class="body">
251
+ {{ content }}
252
+ </div>
253
+ </article>
254
+ </section>
@@ -0,0 +1,4 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ {{ content }}
@@ -0,0 +1,23 @@
1
+ // Code blocks and inline code
2
+
3
+ .documentation .body pre {
4
+ background: #1e293b;
5
+ color: #e2e8f0;
6
+ padding: 1rem 1.25rem;
7
+ border-radius: 0.5rem;
8
+ overflow-x: auto;
9
+ margin: 1.5rem 0;
10
+ }
11
+
12
+ .documentation .body code {
13
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
14
+ font-size: 0.875rem;
15
+ }
16
+
17
+ .documentation .body :not(pre) > code {
18
+ background: #f1f5f9;
19
+ padding: 0.125rem 0.375rem;
20
+ border-radius: 0.25rem;
21
+ color: #1e293b;
22
+ font-size: 0.8125rem;
23
+ }
@@ -0,0 +1,91 @@
1
+ // Dark mode overrides
2
+
3
+ // Layout
4
+ .dark .documentation > article > header {
5
+ border-bottom-color: #334155;
6
+ }
7
+
8
+ .dark .documentation > article > header h1 {
9
+ color: #f8fafc;
10
+ }
11
+
12
+ // Navigation
13
+ .dark .docs-nav .nav-group-title {
14
+ color: #64748b;
15
+ border-top-color: #334155;
16
+ }
17
+
18
+ .dark .docs-nav .nav-items a:hover {
19
+ background: #1e293b;
20
+ color: #f1f5f9;
21
+ }
22
+
23
+ .dark .docs-nav .nav-items a.active {
24
+ background: #312e81;
25
+ color: #a5b4fc;
26
+ }
27
+
28
+ .dark .nav-toggle:hover {
29
+ background: #1e293b;
30
+ color: #f1f5f9;
31
+ }
32
+
33
+ .dark .nav-subsection {
34
+ border-left-color: #334155;
35
+ }
36
+
37
+ // Typography
38
+ .dark .documentation .body h2 {
39
+ color: #f1f5f9;
40
+ }
41
+
42
+ .dark .documentation .body h3 {
43
+ color: #e2e8f0;
44
+ }
45
+
46
+ .dark .documentation .body p {
47
+ color: #94a3b8;
48
+ }
49
+
50
+ .dark .documentation .body ul,
51
+ .dark .documentation .body ol,
52
+ .dark .documentation .body dl,
53
+ .dark .documentation .post-content ul,
54
+ .dark .documentation .post-content ol,
55
+ .dark .documentation .post-content dl,
56
+ .dark .documentation .sectionbody ul,
57
+ .dark .documentation .sectionbody ol,
58
+ .dark .documentation .sectionbody dl {
59
+ color: #94a3b8;
60
+ }
61
+
62
+ .dark .documentation .body li::marker,
63
+ .dark .documentation .post-content li::marker,
64
+ .dark .documentation .sectionbody li::marker {
65
+ color: #818cf8;
66
+ }
67
+
68
+ .dark .documentation .body dt {
69
+ color: #f1f5f9;
70
+ }
71
+
72
+ .dark .documentation .body dd {
73
+ color: #94a3b8;
74
+ }
75
+
76
+ // Code
77
+ .dark .documentation .body :not(pre) > code {
78
+ background: #334155;
79
+ color: #e2e8f0;
80
+ }
81
+
82
+ // Tables
83
+ .dark .documentation .body th,
84
+ .dark .documentation .body td {
85
+ border-bottom-color: #334155;
86
+ }
87
+
88
+ .dark .documentation .body th {
89
+ background: #1e293b;
90
+ color: #f1f5f9;
91
+ }
@@ -0,0 +1,57 @@
1
+ // Documentation layout: two-column flex with sidebar
2
+ .documentation {
3
+ display: flex;
4
+ max-width: 1400px;
5
+ margin: 0 auto;
6
+ margin-top: 64px;
7
+ padding: 2rem 1rem;
8
+ gap: 2rem;
9
+
10
+ @media (min-width: 1024px) {
11
+ padding: 2rem 2rem;
12
+ }
13
+ }
14
+
15
+ // Left sidebar
16
+ .docs-nav {
17
+ width: 220px;
18
+ flex-shrink: 0;
19
+ }
20
+
21
+ // Sticky sidebar content
22
+ @media (min-width: 1024px) {
23
+ .docs-nav-content {
24
+ position: sticky;
25
+ top: 5rem;
26
+ max-height: calc(100vh - 6rem);
27
+ overflow-y: auto;
28
+ }
29
+ }
30
+
31
+ // Main article
32
+ .documentation > article {
33
+ flex: 1;
34
+ min-width: 0;
35
+ max-width: 75ch;
36
+ }
37
+
38
+ .documentation > article > header {
39
+ margin-bottom: 2rem;
40
+ padding-bottom: 1.5rem;
41
+ border-bottom: 1px solid #e2e8f0;
42
+ }
43
+
44
+ .documentation > article > header h1 {
45
+ font-size: 2.25rem;
46
+ font-weight: 700;
47
+ color: #0f172a;
48
+ line-height: 1.2;
49
+ margin: 0;
50
+ }
51
+
52
+ // Hide sidebar on mobile
53
+ @media (max-width: 1023px) {
54
+ .docs-nav {
55
+ display: none;
56
+ }
57
+ }
@@ -0,0 +1,113 @@
1
+ // Sidebar navigation components
2
+
3
+ .docs-nav .nav-section {
4
+ margin-bottom: 1.5rem;
5
+ }
6
+
7
+ .docs-nav .nav-section-title {
8
+ font-size: 0.75rem;
9
+ font-weight: 600;
10
+ text-transform: uppercase;
11
+ letter-spacing: 0.05em;
12
+ color: #94a3b8;
13
+ margin-bottom: 0.5rem;
14
+ padding: 0 0.75rem;
15
+ }
16
+
17
+ // Group headers within navigation
18
+ .docs-nav .nav-group-title {
19
+ font-size: 0.6875rem;
20
+ font-weight: 600;
21
+ text-transform: uppercase;
22
+ letter-spacing: 0.05em;
23
+ color: #94a3b8;
24
+ margin-top: 1rem;
25
+ margin-bottom: 0.25rem;
26
+ padding: 0.25rem 0.75rem;
27
+ border-top: 1px solid #e2e8f0;
28
+ }
29
+
30
+ .docs-nav .nav-group-title:first-child {
31
+ margin-top: 0;
32
+ border-top: none;
33
+ }
34
+
35
+ .docs-nav .nav-items {
36
+ list-style: none;
37
+ padding: 0;
38
+ margin: 0;
39
+ }
40
+
41
+ .docs-nav .nav-items li {
42
+ margin-bottom: 0.125rem;
43
+ }
44
+
45
+ .docs-nav .nav-items a {
46
+ display: block;
47
+ padding: 0.5rem 0.75rem;
48
+ color: #64748b;
49
+ text-decoration: none;
50
+ border-radius: 0.375rem;
51
+ font-size: 0.875rem;
52
+ transition: all 0.15s ease;
53
+ }
54
+
55
+ .docs-nav .nav-items a:hover {
56
+ background: #f1f5f9;
57
+ color: #1e293b;
58
+ }
59
+
60
+ .docs-nav .nav-items a.active {
61
+ background: #eef2ff;
62
+ color: #4f46e5;
63
+ font-weight: 500;
64
+ }
65
+
66
+ // Collapsible subsections
67
+ .nav-subsection {
68
+ margin-left: 0.75rem;
69
+ border-left: 2px solid #e2e8f0;
70
+ padding-left: 0.75rem;
71
+ margin-top: 0.25rem;
72
+ }
73
+
74
+ // Toggle button
75
+ .nav-toggle {
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: space-between;
79
+ padding: 0.5rem 0.75rem;
80
+ color: #64748b;
81
+ font-size: 0.875rem;
82
+ border-radius: 0.375rem;
83
+ cursor: pointer;
84
+ transition: all 0.15s ease;
85
+ user-select: none;
86
+ }
87
+
88
+ .nav-toggle:hover {
89
+ background: #f1f5f9;
90
+ color: #1e293b;
91
+ }
92
+
93
+ // Arrow indicator
94
+ .nav-toggle::after {
95
+ content: '';
96
+ display: inline-block;
97
+ width: 5px;
98
+ height: 5px;
99
+ border-right: 2px solid currentColor;
100
+ border-bottom: 2px solid currentColor;
101
+ transform: rotate(-45deg);
102
+ transition: transform 0.2s ease;
103
+ margin-left: auto;
104
+ flex-shrink: 0;
105
+ }
106
+
107
+ .nav-toggle.open::after {
108
+ transform: rotate(45deg);
109
+ }
110
+
111
+ .nav-subsection.collapsed {
112
+ display: none;
113
+ }
@@ -0,0 +1,20 @@
1
+ // Table styling
2
+
3
+ .documentation .body table {
4
+ width: 100%;
5
+ border-collapse: collapse;
6
+ margin: 1.5rem 0;
7
+ }
8
+
9
+ .documentation .body th,
10
+ .documentation .body td {
11
+ padding: 0.75rem 1rem;
12
+ text-align: left;
13
+ border-bottom: 1px solid #e2e8f0;
14
+ }
15
+
16
+ .documentation .body th {
17
+ background: #f8fafc;
18
+ font-weight: 600;
19
+ color: #1e293b;
20
+ }
@@ -0,0 +1,112 @@
1
+ // Documentation body typography
2
+
3
+ .documentation .body {
4
+ font-size: 1rem;
5
+ line-height: 1.75;
6
+ }
7
+
8
+ .documentation .body h2 {
9
+ font-size: 1.5rem;
10
+ font-weight: 600;
11
+ margin-top: 2.5rem;
12
+ margin-bottom: 1rem;
13
+ color: #1e293b;
14
+ }
15
+
16
+ .documentation .body h3 {
17
+ font-size: 1.25rem;
18
+ font-weight: 600;
19
+ margin-top: 2rem;
20
+ margin-bottom: 0.75rem;
21
+ color: #334155;
22
+ }
23
+
24
+ .documentation .body p {
25
+ margin-bottom: 1rem;
26
+ color: #475569;
27
+ }
28
+
29
+ .documentation .body a {
30
+ color: #6366f1;
31
+ text-decoration: underline;
32
+ text-underline-offset: 2px;
33
+ }
34
+
35
+ .documentation .body a:hover {
36
+ color: #4f46e5;
37
+ }
38
+
39
+ // Lists
40
+ .documentation .body ul,
41
+ .documentation .body ol,
42
+ .documentation .body dl,
43
+ .documentation .post-content ul,
44
+ .documentation .post-content ol,
45
+ .documentation .post-content dl,
46
+ .documentation .sectionbody ul,
47
+ .documentation .sectionbody ol,
48
+ .documentation .sectionbody dl {
49
+ margin-bottom: 1.25rem;
50
+ padding-left: 1.75rem;
51
+ color: #475569;
52
+ list-style-position: outside;
53
+ }
54
+
55
+ .documentation .body ul,
56
+ .documentation .post-content ul,
57
+ .documentation .sectionbody ul {
58
+ list-style-type: disc !important;
59
+ }
60
+
61
+ .documentation .body ul ul,
62
+ .documentation .post-content ul ul,
63
+ .documentation .sectionbody ul ul {
64
+ list-style-type: circle !important;
65
+ margin-top: 0.5rem;
66
+ margin-bottom: 0.5rem;
67
+ }
68
+
69
+ .documentation .body ol,
70
+ .documentation .post-content ol,
71
+ .documentation .sectionbody ol {
72
+ list-style-type: decimal !important;
73
+ }
74
+
75
+ // Exception: don't number breadcrumb navigation
76
+ .body nav[aria-label="Breadcrumb"] ol,
77
+ .body nav ol.list-none,
78
+ ol.list-none {
79
+ list-style: none !important;
80
+ padding-left: 0 !important;
81
+ }
82
+
83
+ .body nav[aria-label="Breadcrumb"] li,
84
+ .body nav ol.list-none li {
85
+ margin-bottom: 0 !important;
86
+ }
87
+
88
+ .documentation .body li,
89
+ .documentation .post-content li,
90
+ .documentation .sectionbody li {
91
+ margin-bottom: 0.625rem;
92
+ line-height: 1.7;
93
+ }
94
+
95
+ .documentation .body li::marker,
96
+ .documentation .post-content li::marker,
97
+ .documentation .sectionbody li::marker {
98
+ color: #6366f1;
99
+ }
100
+
101
+ // Definition lists
102
+ .documentation .body dt {
103
+ font-weight: 600;
104
+ color: #1e293b;
105
+ margin-bottom: 0.25rem;
106
+ }
107
+
108
+ .documentation .body dd {
109
+ margin-left: 1.5rem;
110
+ margin-bottom: 0.75rem;
111
+ color: #475569;
112
+ }
@@ -0,0 +1,6 @@
1
+ @import 'calconnect/layout';
2
+ @import 'calconnect/navigation';
3
+ @import 'calconnect/typography';
4
+ @import 'calconnect/code';
5
+ @import 'calconnect/tables';
6
+ @import 'calconnect/dark-mode';
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "calconnect-theme"
5
+ spec.version = "0.1.0"
6
+ spec.authors = ["CalConnect"]
7
+ spec.email = ["info@calconnect.org"]
8
+ spec.summary = "Shared Jekyll theme for CalConnect sites"
9
+ spec.homepage = "https://github.com/calconnect/calconnect-theme"
10
+ spec.license = "MIT"
11
+
12
+ spec.files = Dir[
13
+ "{_layouts,_includes,_sass,_frontend}/**/*",
14
+ "*.md",
15
+ "*.gemspec"
16
+ ]
17
+
18
+ spec.add_runtime_dependency "jekyll", "~> 4.3"
19
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: calconnect-theme
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - CalConnect
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: jekyll
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '4.3'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '4.3'
26
+ email:
27
+ - info@calconnect.org
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - README.md
33
+ - _frontend/entrypoints/application.css
34
+ - _frontend/entrypoints/application.js
35
+ - _frontend/js/navigation.js
36
+ - _frontend/js/theme.js
37
+ - _includes/breadcrumbs.html
38
+ - _includes/custom-head.html
39
+ - _includes/feedback.html
40
+ - _includes/footer.html
41
+ - _includes/google-analytics.html
42
+ - _includes/head.html
43
+ - _includes/header.html
44
+ - _layouts/base.html
45
+ - _layouts/default.html
46
+ - _layouts/page.html
47
+ - _sass/calconnect.scss
48
+ - _sass/calconnect/_code.scss
49
+ - _sass/calconnect/_dark-mode.scss
50
+ - _sass/calconnect/_layout.scss
51
+ - _sass/calconnect/_navigation.scss
52
+ - _sass/calconnect/_tables.scss
53
+ - _sass/calconnect/_typography.scss
54
+ - jekyll-calconnect-theme.gemspec
55
+ homepage: https://github.com/calconnect/calconnect-theme
56
+ licenses:
57
+ - MIT
58
+ metadata: {}
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubygems_version: 3.6.9
74
+ specification_version: 4
75
+ summary: Shared Jekyll theme for CalConnect sites
76
+ test_files: []