insights4you-jekyll-theme 0.1.1 → 0.2.2

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.
data/assets/js/theme.js CHANGED
@@ -1,31 +1,194 @@
1
- /**
2
- * demo-theme is specifically loaded right after the body and not deferred
3
- * to ensure we switch to the chosen dark/light theme as fast as possible.
4
- * This will prevent any flashes of the light theme (default) before switching.
5
- */
1
+ // Ensure jsyaml is available
2
+ /* eslint-disable no-undef */ // Disable undefined variable check for 'jsyaml'
3
+ if (typeof jsyaml === "undefined") {
4
+ throw new Error("js-yaml library is not loaded. Please include it in your project.");
5
+ }
6
+ /* eslint-enable no-undef */
6
7
 
7
8
  const THEME_STORAGE_KEY = "tablerTheme";
8
- const defaultTheme = "light";
9
- let selectedTheme;
9
+ const DEFAULT_THEME = "light";
10
10
 
11
- // https://stackoverflow.com/a/901144
12
- // Create a Proxy for URLSearchParams to simplify access to query parameters.
13
- // This allows us to use `params.key` instead of `params.get('key')`.
11
+ // Proxy to access URL parameters securely
14
12
  const params = new Proxy(new URLSearchParams(window.location.search), {
15
- get: (searchParams, prop) => searchParams.get(prop)
13
+ get: (searchParams, prop) => searchParams.get(prop),
16
14
  });
17
15
 
18
- if (params.theme) {
19
- localStorage.setItem(THEME_STORAGE_KEY, params.theme);
20
- selectedTheme = params.theme;
21
- } else {
22
- const storedTheme = localStorage.getItem(THEME_STORAGE_KEY);
23
- selectedTheme = storedTheme || defaultTheme;
16
+ // Validate theme values
17
+ function isValidTheme(theme) {
18
+ return ["light", "dark"].includes(theme);
19
+ }
20
+
21
+ // Apply the selected theme to the document
22
+ function applyTheme(theme) {
23
+ document.body.setAttribute("data-bs-theme", theme);
24
+
25
+ // Accessibility: Notify screen readers of theme change
26
+ const themeAnnouncement = document.getElementById("theme-announcement");
27
+ if (themeAnnouncement) {
28
+ themeAnnouncement.textContent = `Theme changed to ${theme}`;
29
+ }
30
+ }
31
+
32
+ // Save the selected theme to localStorage
33
+ function saveTheme(theme) {
34
+ localStorage.setItem(THEME_STORAGE_KEY, theme);
35
+ }
36
+
37
+ // Load the current theme based on priority: URL > localStorage > system preference > default
38
+ function loadTheme() {
39
+ let selectedTheme;
40
+
41
+ // Prioritize theme from URL (sanitize input to prevent XSS)
42
+ if (params.theme && isValidTheme(params.theme)) {
43
+ selectedTheme = params.theme;
44
+ saveTheme(selectedTheme);
45
+ } else {
46
+ // Use localStorage or system preference
47
+ const storedTheme = localStorage.getItem(THEME_STORAGE_KEY);
48
+ selectedTheme = isValidTheme(storedTheme)
49
+ ? storedTheme
50
+ : window.matchMedia("(prefers-color-scheme: dark)").matches
51
+ ? "dark"
52
+ : DEFAULT_THEME;
53
+ }
54
+
55
+ // Apply the selected theme
56
+ applyTheme(selectedTheme);
57
+ }
58
+
59
+ // Toggle between light and dark themes
60
+ /* eslint-disable no-unused-vars */ // Disable unused function check for 'toggleTheme'
61
+ function toggleTheme(theme) {
62
+ saveTheme(theme);
63
+ applyTheme(theme);
64
+ }
65
+ /* eslint-enable no-unused-vars */
66
+
67
+ // Load dynamic notifications
68
+ async function loadNotifications() {
69
+ const notificationsList = document.getElementById("notifications-list");
70
+ const badge = document.getElementById("notification-badge");
71
+
72
+ if (!notificationsList || !badge) return;
73
+
74
+ try {
75
+ // Fetch local and remote notifications
76
+ const [localNotifications, remoteNotifications] = await Promise.all([
77
+ getLocalNotifications(),
78
+ fetchRemoteNotifications(),
79
+ ]);
80
+
81
+ // Combine, sort, and render notifications
82
+ const allNotifications = combineAndSortNotifications(localNotifications, remoteNotifications);
83
+ renderNotifications(allNotifications, notificationsList, badge);
84
+ } catch (error) {
85
+ console.error("Error loading notifications:", error);
86
+ }
87
+ }
88
+
89
+ // Fetch local notifications from site data
90
+ function getLocalNotifications() {
91
+ try {
92
+ return Array.isArray(window.siteData?.notifications) ? window.siteData.notifications : [];
93
+ } catch (error) {
94
+ console.error("Error loading local notifications:", error);
95
+ return [];
96
+ }
97
+ }
98
+
99
+ // Fetch remote notifications from GitHub repository
100
+ async function fetchRemoteNotifications() {
101
+ try {
102
+ const response = await fetch(
103
+ "https://raw.githubusercontent.com/marciopaiva/insights4you-jekyll-theme/main/_data/notifications.yml"
104
+ );
105
+ if (!response.ok) throw new Error("Failed to fetch remote notifications");
106
+ const yamlText = await response.text();
107
+ /* eslint-disable no-undef */ // Disable undefined variable check for 'jsyaml'
108
+ const parsedData = jsyaml.load(yamlText); // Parse YAML data
109
+ /* eslint-enable no-undef */
110
+ return Array.isArray(parsedData) ? parsedData : [];
111
+ } catch (error) {
112
+ console.error("Error fetching remote notifications:", error);
113
+ return [];
114
+ }
115
+ }
116
+
117
+ // Combine and sort notifications by date
118
+ function combineAndSortNotifications(local, remote) {
119
+ return [...remote, ...local]
120
+ .filter((notification) => notification.date) // Ensure each notification has a valid date
121
+ .sort((a, b) => new Date(b.date) - new Date(a.date))
122
+ .slice(0, 5); // Display only the latest 5 notifications
123
+ }
124
+
125
+ // Render notifications in the DOM securely
126
+ function renderNotifications(notifications, listElement, badgeElement) {
127
+ badgeElement.textContent = notifications.length;
128
+
129
+ // Clear existing notifications
130
+ listElement.innerHTML = "";
131
+
132
+ // Append notifications using DOM manipulation for security
133
+ notifications.forEach((notification) => {
134
+ const item = createNotificationItem(notification);
135
+ listElement.appendChild(item);
136
+ });
137
+ }
138
+
139
+ // Create a single notification item securely
140
+ function createNotificationItem(notification) {
141
+ const container = document.createElement("div");
142
+ container.className = "list-group-item";
143
+
144
+ const row = document.createElement("div");
145
+ row.className = "row align-items-center";
146
+
147
+ const colAuto = document.createElement("div");
148
+ colAuto.className = "col-auto";
149
+ const statusDot = document.createElement("span");
150
+ statusDot.className = `status-dot bg-${notification.color || "blue"} d-block`;
151
+ colAuto.appendChild(statusDot);
152
+
153
+ const colText = document.createElement("div");
154
+ colText.className = "col text-truncate";
155
+ const title = document.createElement("a");
156
+ title.href = notification.link;
157
+ title.className = "text-body d-block";
158
+ title.textContent = notification.title || "Untitled Notification";
159
+ const description = document.createElement("div");
160
+ description.className = "text-secondary";
161
+ description.textContent = notification.description || "No description available";
162
+ const date = document.createElement("small");
163
+ date.className = "text-muted";
164
+ date.textContent = new Date(notification.date).toLocaleDateString();
165
+ colText.append(title, description, date);
166
+
167
+ const colActions = document.createElement("div");
168
+ colActions.className = "col-auto";
169
+ const actionLink = document.createElement("a");
170
+ actionLink.href = notification.link;
171
+ actionLink.className = "list-group-item-actions";
172
+ actionLink.target = "_blank";
173
+ const svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
174
+ svgIcon.setAttribute("class", "icon text-muted icon-2");
175
+ svgIcon.setAttribute("viewBox", "0 0 24 24");
176
+ svgIcon.setAttribute("stroke", "currentColor");
177
+ svgIcon.setAttribute("fill", "none");
178
+ const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
179
+ path.setAttribute("d", "M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z");
180
+ svgIcon.appendChild(path);
181
+ actionLink.appendChild(svgIcon);
182
+ colActions.appendChild(actionLink);
183
+
184
+ row.append(colAuto, colText, colActions);
185
+ container.appendChild(row);
186
+
187
+ return container;
24
188
  }
25
189
 
26
- // Apply the selected theme to the document body
27
- if (selectedTheme === "dark") {
28
- document.body.setAttribute("data-bs-theme", "dark");
29
- } else if (selectedTheme === "light") {
30
- document.body.setAttribute("data-bs-theme", "light");
31
- }
190
+ // Initialize theme and notifications when the page loads
191
+ document.addEventListener("DOMContentLoaded", () => {
192
+ loadTheme();
193
+ loadNotifications();
194
+ });
metadata CHANGED
@@ -1,35 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: insights4you-jekyll-theme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcio Paiva Barbosa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-20 00:00:00.000000000 Z
11
+ date: 2025-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '3.9'
20
- - - "<"
17
+ - - "~>"
21
18
  - !ruby/object:Gem::Version
22
- version: '5.0'
19
+ version: 4.4.1
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: '3.9'
30
- - - "<"
26
+ version: 4.4.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: jekyll-feed
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
31
32
  - !ruby/object:Gem::Version
32
- version: '5.0'
33
+ version: '0.15'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.15'
33
41
  - !ruby/object:Gem::Dependency
34
42
  name: jekyll-seo-tag
35
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,10 +66,53 @@ dependencies:
58
66
  - - "~>"
59
67
  - !ruby/object:Gem::Version
60
68
  version: '2.4'
61
- description: A professional and responsive Jekyll theme designed for documentation
62
- sites, admin panels, and project showcases. It includes customizable layouts, modern
63
- design elements, and support for responsive design to ensure compatibility across
64
- devices.
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.50'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.50'
111
+ description: "A sleek and modern Jekyll theme inspired by the Tabler Admin Dashboard.
112
+ \nThis theme offers a clean, professional, and responsive interface, making it ideal
113
+ for developers, \ncontent creators, and businesses. Whether you're building documentation
114
+ sites, admin panels, or \nproject showcases, this theme provides a minimal-effort
115
+ solution with customizable layouts and \nmodern design elements.\n"
65
116
  email:
66
117
  - mpaivabarbosa@gmail.com
67
118
  executables: []
@@ -70,11 +121,35 @@ extra_rdoc_files: []
70
121
  files:
71
122
  - LICENSE
72
123
  - README.md
124
+ - _data/i4y-errors.json
125
+ - _data/i4y-icons.json
126
+ - _data/i4y-illustrations.json
127
+ - _data/i4y-social-media.yml
128
+ - _data/notifications.yml
129
+ - _includes/card/profile.html
73
130
  - _includes/footer.html
74
- - _includes/header.html
75
- - _includes/sidebar.html
76
- - _layouts/base.html
131
+ - _includes/head.html
132
+ - _includes/header-logo.html
133
+ - _includes/header-navbar.html
134
+ - _includes/header-svg.html
135
+ - _includes/ui/button.html
136
+ - _includes/ui/empty.html
137
+ - _includes/ui/icon.html
138
+ - _includes/ui/illustration.html
139
+ - _layouts/default.html
140
+ - _layouts/error.html
141
+ - _layouts/home.html
142
+ - _layouts/post.html
77
143
  - assets/css/theme.min.css
144
+ - assets/images/android-chrome-192x192.png
145
+ - assets/images/android-chrome-512x512.png
146
+ - assets/images/apple-touch-icon.png
147
+ - assets/images/favicon-16x16.png
148
+ - assets/images/favicon-32x32.png
149
+ - assets/images/favicon.ico
150
+ - assets/images/i4y-logo.jpg
151
+ - assets/images/preview-dark.png
152
+ - assets/images/site.webmanifest
78
153
  - assets/js/theme.js
79
154
  homepage: https://github.com/marciopaiva/insights4you-jekyll-theme
80
155
  licenses:
@@ -84,7 +159,11 @@ metadata:
84
159
  documentation_uri: https://github.com/marciopaiva/insights4you-jekyll-theme/#readme
85
160
  source_code_uri: https://github.com/marciopaiva/insights4you-jekyll-theme
86
161
  wiki_uri: https://github.com/marciopaiva/insights4you-jekyll-theme/wiki
162
+ changelog_uri: https://github.com/marciopaiva/insights4you-jekyll-theme/blob/main/CHANGELOG.md
87
163
  plugin_type: theme
164
+ funding_uri: https://github.com/sponsors/marciopaiva
165
+ usage_uri: https://github.com/marciopaiva/insights4you-jekyll-theme/wiki/Usage
166
+ examples_uri: https://github.com/marciopaiva/insights4you-jekyll-theme/tree/main/example-site
88
167
  post_install_message:
89
168
  rdoc_options: []
90
169
  require_paths:
@@ -93,14 +172,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
172
  requirements:
94
173
  - - "~>"
95
174
  - !ruby/object:Gem::Version
96
- version: '3.1'
175
+ version: '3.0'
97
176
  required_rubygems_version: !ruby/object:Gem::Requirement
98
177
  requirements:
99
178
  - - ">="
100
179
  - !ruby/object:Gem::Version
101
180
  version: '0'
102
181
  requirements: []
103
- rubygems_version: 3.3.26
182
+ rubygems_version: 3.3.7
104
183
  signing_key:
105
184
  specification_version: 4
106
185
  summary: A sleek and modern Jekyll theme inspired by the Tabler Admin Dashboard.