rollout-ui 0.9.1 → 0.9.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.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b5230ac819ea0e86c7dc2606f9b308c429b6b92b50e8fb402ac3b4f5519b8207
|
|
4
|
+
data.tar.gz: 67f902bcffbc98e99189b16c577c66952bde58b0dfff550318cadcb0779f9bc3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: af0154118022337d0963bb63013498f2292fecfe29dfd318729335fd724c4e4569e2c7a3f6662c19ce0c9ba729fd9a0149005963cbc531c3ae800b55077a8fa8
|
|
7
|
+
data.tar.gz: 85d005cfbf60f08c96032e3a4b9c607aca322f013050845489974c21a19a88259d68a98d011774e75c4c7d2e6f692969c3ee7daadffb6542a31bc2d144f49409
|
data/lib/rollout/ui/helpers.rb
CHANGED
|
@@ -70,6 +70,16 @@ module Rollout::UI
|
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
def formatted_timestamp(time)
|
|
74
|
+
time.strftime(config.get(:timestamp_format))
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def relative_timestamp_tag(time)
|
|
78
|
+
return "" unless time
|
|
79
|
+
|
|
80
|
+
%(<span data-timestamp="#{h(time.iso8601)}" title="#{h(formatted_timestamp(time))}">#{h(time_ago(time))}</span>)
|
|
81
|
+
end
|
|
82
|
+
|
|
73
83
|
def format_change_key(key)
|
|
74
84
|
key.to_s.gsub('data.', '')
|
|
75
85
|
end
|
data/lib/rollout/ui/version.rb
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
<% if updated_at.nil? %>
|
|
50
50
|
<span class="text-gray-400">Never</span>
|
|
51
51
|
<% else %>
|
|
52
|
-
|
|
52
|
+
<%= relative_timestamp_tag(updated_at) %>
|
|
53
53
|
<% end %>
|
|
54
54
|
</td>
|
|
55
55
|
<% end %>
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
</td>
|
|
56
56
|
|
|
57
57
|
<td class="py-2 text-right whitespace-nowrap pl-3" style="min-width: 160px;">
|
|
58
|
-
|
|
58
|
+
<%= relative_timestamp_tag(event.created_at) %>
|
|
59
59
|
</td>
|
|
60
60
|
</tr>
|
|
61
61
|
<% end %>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
2
|
+
<html data-timestamp-format="<%= h(config.get(:timestamp_format)) %>">
|
|
3
3
|
<head>
|
|
4
4
|
<title>Rollout UI</title>
|
|
5
5
|
<meta name="viewport" content="width=device-width initial-scale=1">
|
|
@@ -42,19 +42,85 @@
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
applyTheme(theme);
|
|
45
|
+
const themeLabels = { system: 'Theme: System', light: 'Theme: Light', dark: 'Theme: Dark' };
|
|
46
|
+
const themeTitles = {
|
|
47
|
+
system: "Follows your device's light or dark appearance setting.",
|
|
48
|
+
light: 'Always use light appearance.',
|
|
49
|
+
dark: 'Always use dark appearance.'
|
|
50
|
+
};
|
|
45
51
|
window.addEventListener('DOMContentLoaded', function() {
|
|
46
52
|
const btn = document.getElementById('theme-toggle');
|
|
47
|
-
|
|
53
|
+
function applyThemeLabel(t) {
|
|
54
|
+
btn.textContent = themeLabels[t];
|
|
55
|
+
btn.title = themeTitles[t];
|
|
56
|
+
}
|
|
57
|
+
applyThemeLabel(theme);
|
|
48
58
|
btn.addEventListener('click', function() {
|
|
49
59
|
const current = localStorage.getItem('theme') || 'system';
|
|
50
60
|
const next = current === 'light' ? 'dark' : current === 'dark' ? 'system' : 'light';
|
|
51
61
|
localStorage.setItem('theme', next);
|
|
52
62
|
applyTheme(next);
|
|
53
|
-
|
|
63
|
+
applyThemeLabel(next);
|
|
54
64
|
});
|
|
55
65
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function() {
|
|
56
66
|
if (localStorage.getItem('theme') === 'system') applyTheme('system');
|
|
57
67
|
});
|
|
68
|
+
|
|
69
|
+
const timezoneKey = 'timezone';
|
|
70
|
+
const timezoneBtn = document.getElementById('timezone-toggle');
|
|
71
|
+
function timezoneMode() {
|
|
72
|
+
return localStorage.getItem(timezoneKey) === 'utc' ? 'utc' : 'local';
|
|
73
|
+
}
|
|
74
|
+
function formatTimestamp(iso, mode) {
|
|
75
|
+
const date = new Date(iso);
|
|
76
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
77
|
+
const format = document.documentElement.getAttribute('data-timestamp-format') || '%Y-%m-%d %H:%M %Z';
|
|
78
|
+
const parts = {};
|
|
79
|
+
new Intl.DateTimeFormat('en-US', {
|
|
80
|
+
year: 'numeric',
|
|
81
|
+
month: '2-digit',
|
|
82
|
+
day: '2-digit',
|
|
83
|
+
hour: '2-digit',
|
|
84
|
+
minute: '2-digit',
|
|
85
|
+
second: '2-digit',
|
|
86
|
+
hourCycle: 'h23',
|
|
87
|
+
timeZone: mode === 'utc' ? 'UTC' : undefined,
|
|
88
|
+
timeZoneName: 'short'
|
|
89
|
+
}).formatToParts(date).forEach(function(part) {
|
|
90
|
+
if (part.type !== 'literal') parts[part.type] = part.value;
|
|
91
|
+
});
|
|
92
|
+
const tokens = {
|
|
93
|
+
'%Y': parts.year,
|
|
94
|
+
'%y': parts.year.slice(-2),
|
|
95
|
+
'%m': parts.month,
|
|
96
|
+
'%d': parts.day,
|
|
97
|
+
'%H': parts.hour,
|
|
98
|
+
'%M': parts.minute,
|
|
99
|
+
'%S': parts.second,
|
|
100
|
+
'%Z': parts.timeZoneName,
|
|
101
|
+
'%%': '%'
|
|
102
|
+
};
|
|
103
|
+
return format.replace(/%[%YymdHMSZ]/g, function(token) {
|
|
104
|
+
return Object.prototype.hasOwnProperty.call(tokens, token) ? tokens[token] : token;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function applyTimezone(mode) {
|
|
108
|
+
const localZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'Local';
|
|
109
|
+
timezoneBtn.textContent = mode === 'utc' ? 'Time: UTC' : 'Time: Local';
|
|
110
|
+
timezoneBtn.title = mode === 'utc'
|
|
111
|
+
? 'Uses Coordinated Universal Time.'
|
|
112
|
+
: "Uses your browser's timezone: " + localZone;
|
|
113
|
+
document.querySelectorAll('[data-timestamp]').forEach(function(el) {
|
|
114
|
+
const formatted = formatTimestamp(el.getAttribute('data-timestamp'), mode);
|
|
115
|
+
if (formatted) el.setAttribute('title', formatted);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
applyTimezone(timezoneMode());
|
|
119
|
+
timezoneBtn.addEventListener('click', function() {
|
|
120
|
+
const next = timezoneMode() === 'local' ? 'utc' : 'local';
|
|
121
|
+
localStorage.setItem(timezoneKey, next);
|
|
122
|
+
applyTimezone(next);
|
|
123
|
+
});
|
|
58
124
|
});
|
|
59
125
|
})();
|
|
60
126
|
</script>
|
|
@@ -63,7 +129,8 @@
|
|
|
63
129
|
<h1 class="font-light text-4xl text-gray-600 flex-auto">
|
|
64
130
|
<a href="<%= h(index_path) %>" class="hover:text-blue-700">Rollout </a>
|
|
65
131
|
</h1>
|
|
66
|
-
<button id="
|
|
132
|
+
<button type="button" id="timezone-toggle" class="text-sm text-gray-600 p-2 bg-gray-100 rounded-sm transition-colors duration-150 hover:bg-gray-200 mr-2" title="Uses your browser's timezone">Time: Local</button>
|
|
133
|
+
<button type="button" id="theme-toggle" class="text-sm text-gray-600 p-2 bg-gray-100 rounded-sm transition-colors duration-150 hover:bg-gray-200" title="Follows your device's light or dark appearance setting.">Theme: System</button>
|
|
67
134
|
</div>
|
|
68
135
|
<%= yield %>
|
|
69
136
|
</div>
|