@dmthepm/commune 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.
- package/LICENSE +21 -0
- package/README.md +468 -0
- package/bin/commune.mjs +29 -0
- package/lib/cli/check.d.ts +13 -0
- package/lib/cli/check.js +58 -0
- package/lib/cli/errors.d.ts +29 -0
- package/lib/cli/errors.js +41 -0
- package/lib/cli/gate.d.ts +34 -0
- package/lib/cli/gate.js +165 -0
- package/lib/cli/main.d.ts +20 -0
- package/lib/cli/main.js +175 -0
- package/lib/cli/query.d.ts +30 -0
- package/lib/cli/query.js +103 -0
- package/lib/cli/related.d.ts +17 -0
- package/lib/cli/related.js +177 -0
- package/lib/cli/render.d.ts +20 -0
- package/lib/cli/render.js +32 -0
- package/lib/cli/root.d.ts +11 -0
- package/lib/cli/root.js +28 -0
- package/lib/cli/usage.d.ts +3 -0
- package/lib/cli/usage.js +46 -0
- package/lib/cli/version.d.ts +24 -0
- package/lib/cli/version.js +29 -0
- package/lib/integration.d.ts +24 -0
- package/lib/integration.js +111 -0
- package/lib/lib/graph.d.ts +354 -0
- package/lib/lib/graph.js +774 -0
- package/lib/markdown.d.ts +30 -0
- package/lib/markdown.js +24 -0
- package/lib/rehype-external-links.d.ts +15 -0
- package/lib/rehype-external-links.js +46 -0
- package/lib/remark-wikilinks.d.ts +25 -0
- package/lib/remark-wikilinks.js +108 -0
- package/package.json +101 -0
- package/src/components/Backlinks.astro +17 -0
- package/src/components/BacklinksScript.astro +117 -0
- package/src/components/Footer.astro +35 -0
- package/src/components/Header.astro +250 -0
- package/src/components/HeaderStarScript.astro +380 -0
- package/src/components/HomeFooterCards.astro +155 -0
- package/src/components/MarkdownLink.astro +36 -0
- package/src/components/PlausibleScript.astro +13 -0
- package/src/components/RelatedNotes.astro +77 -0
- package/src/components/SearchModal.astro +213 -0
- package/src/components/StarredLinksScript.astro +92 -0
- package/src/components/panes.ts +61 -0
- package/src/styles/design-system.css +157 -0
- package/src/styles/notes.css +85 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
---
|
|
3
|
+
<header class="commune-header">
|
|
4
|
+
<div class="wrap">
|
|
5
|
+
<a href="/" class="brand-section">
|
|
6
|
+
<img src="/avatar.jpg" alt="Devon" class="avatar" />
|
|
7
|
+
<span class="brand brand-full">Devon Meadows</span>
|
|
8
|
+
<span class="brand brand-short">Devon</span>
|
|
9
|
+
</a>
|
|
10
|
+
<div class="controls">
|
|
11
|
+
<button id="theme-toggle" class="theme-btn" aria-label="Toggle theme">
|
|
12
|
+
<span class="sun">☀️</span>
|
|
13
|
+
<span class="moon">🌙</span>
|
|
14
|
+
</button>
|
|
15
|
+
<button class="search-btn" aria-label="Search (⌘K)" onclick="window.dispatchEvent(new CustomEvent('commune:openSearch'))">
|
|
16
|
+
<span class="search-icon">🔍</span>
|
|
17
|
+
<span class="search-text">Search</span><kbd>⌘K</kbd>
|
|
18
|
+
</button>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</header>
|
|
22
|
+
|
|
23
|
+
<style>
|
|
24
|
+
.commune-header{
|
|
25
|
+
position:sticky;
|
|
26
|
+
top:0;
|
|
27
|
+
background:var(--c-bg);
|
|
28
|
+
backdrop-filter:saturate(120%) blur(12px);
|
|
29
|
+
border-bottom:1px solid var(--c-border);
|
|
30
|
+
z-index:var(--z-header);
|
|
31
|
+
box-shadow:var(--c-shadow-sm);
|
|
32
|
+
}
|
|
33
|
+
.wrap{
|
|
34
|
+
display:flex;
|
|
35
|
+
align-items:center;
|
|
36
|
+
gap:1rem;
|
|
37
|
+
justify-content:space-between;
|
|
38
|
+
padding:1rem 1.25rem;
|
|
39
|
+
max-width:clamp(480px, 45vw, 700px);
|
|
40
|
+
margin:0 auto;
|
|
41
|
+
}
|
|
42
|
+
.brand-section{
|
|
43
|
+
display:flex;
|
|
44
|
+
align-items:center;
|
|
45
|
+
gap:.75rem;
|
|
46
|
+
text-decoration:none;
|
|
47
|
+
color:inherit;
|
|
48
|
+
}
|
|
49
|
+
.avatar{
|
|
50
|
+
width:2.5rem;
|
|
51
|
+
height:2.5rem;
|
|
52
|
+
border-radius:50%;
|
|
53
|
+
object-fit:cover;
|
|
54
|
+
border:2px solid var(--c-border);
|
|
55
|
+
transition:border-color 0.15s ease;
|
|
56
|
+
}
|
|
57
|
+
.avatar:hover{
|
|
58
|
+
border-color:var(--c-accent);
|
|
59
|
+
}
|
|
60
|
+
.controls{
|
|
61
|
+
display:flex;
|
|
62
|
+
align-items:center;
|
|
63
|
+
gap:.75rem;
|
|
64
|
+
}
|
|
65
|
+
.brand{
|
|
66
|
+
font-weight:700;
|
|
67
|
+
font-size:1.15rem;
|
|
68
|
+
letter-spacing:.3px;
|
|
69
|
+
color:var(--c-text);
|
|
70
|
+
cursor:pointer;
|
|
71
|
+
transition:color 0.15s ease;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Show full name on desktop, hide short name */
|
|
75
|
+
.brand-short {
|
|
76
|
+
display: none;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Tablet and below: remove max-width to match body full-width layout */
|
|
80
|
+
@media (max-width: 1023px) {
|
|
81
|
+
.wrap {
|
|
82
|
+
max-width: none;
|
|
83
|
+
padding:1rem 1.5rem;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Mobile: show short name, hide full name */
|
|
88
|
+
@media (max-width: 768px) {
|
|
89
|
+
.brand-full {
|
|
90
|
+
display: none;
|
|
91
|
+
}
|
|
92
|
+
.brand-short {
|
|
93
|
+
display: block;
|
|
94
|
+
font-size:1.1rem;
|
|
95
|
+
font-weight:600;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
.brand:hover{
|
|
99
|
+
color:var(--c-accent);
|
|
100
|
+
}
|
|
101
|
+
nav{
|
|
102
|
+
display:flex;
|
|
103
|
+
gap:1.25rem;
|
|
104
|
+
}
|
|
105
|
+
nav a{
|
|
106
|
+
color:var(--c-text);
|
|
107
|
+
font-weight:500;
|
|
108
|
+
cursor:pointer;
|
|
109
|
+
transition:color 0.15s ease;
|
|
110
|
+
}
|
|
111
|
+
nav a:hover{
|
|
112
|
+
color:var(--c-accent);
|
|
113
|
+
}
|
|
114
|
+
.theme-btn{
|
|
115
|
+
display:flex;
|
|
116
|
+
align-items:center;
|
|
117
|
+
justify-content:center;
|
|
118
|
+
width:2.5rem;
|
|
119
|
+
height:2.5rem;
|
|
120
|
+
border:1.5px solid var(--c-border);
|
|
121
|
+
background:var(--c-bg-soft);
|
|
122
|
+
border-radius:var(--c-radius-md);
|
|
123
|
+
cursor:pointer;
|
|
124
|
+
transition:all 0.15s ease;
|
|
125
|
+
font-size:1.2rem;
|
|
126
|
+
position:relative;
|
|
127
|
+
}
|
|
128
|
+
.theme-btn:hover{
|
|
129
|
+
border-color:var(--c-accent);
|
|
130
|
+
transform:rotate(15deg);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Mobile: prevent rotate transform issues on touch */
|
|
134
|
+
@media (max-width: 768px) {
|
|
135
|
+
.theme-btn:hover {
|
|
136
|
+
transform:none;
|
|
137
|
+
}
|
|
138
|
+
.theme-btn:active {
|
|
139
|
+
transform:scale(0.95);
|
|
140
|
+
transition:transform 0.1s ease;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
.theme-btn .sun,
|
|
144
|
+
.theme-btn .moon{
|
|
145
|
+
position:absolute;
|
|
146
|
+
transition:opacity 0.2s ease, transform 0.2s ease;
|
|
147
|
+
}
|
|
148
|
+
:root[data-theme="light"] .theme-btn .sun{
|
|
149
|
+
opacity:1;
|
|
150
|
+
transform:rotate(0deg);
|
|
151
|
+
}
|
|
152
|
+
:root[data-theme="light"] .theme-btn .moon{
|
|
153
|
+
opacity:0;
|
|
154
|
+
transform:rotate(180deg);
|
|
155
|
+
}
|
|
156
|
+
:root[data-theme="dark"] .theme-btn .sun{
|
|
157
|
+
opacity:0;
|
|
158
|
+
transform:rotate(180deg);
|
|
159
|
+
}
|
|
160
|
+
:root[data-theme="dark"] .theme-btn .moon{
|
|
161
|
+
opacity:1;
|
|
162
|
+
transform:rotate(0deg);
|
|
163
|
+
}
|
|
164
|
+
.search-btn{
|
|
165
|
+
display:flex;
|
|
166
|
+
align-items:center;
|
|
167
|
+
gap:.6rem;
|
|
168
|
+
border:1.5px solid var(--c-border);
|
|
169
|
+
background:var(--c-bg-soft);
|
|
170
|
+
padding:.5rem .8rem;
|
|
171
|
+
border-radius:var(--c-radius-md);
|
|
172
|
+
cursor:pointer;
|
|
173
|
+
transition:all 0.15s ease;
|
|
174
|
+
}
|
|
175
|
+
.search-btn:hover{
|
|
176
|
+
border-color:var(--c-accent);
|
|
177
|
+
background:var(--c-bg);
|
|
178
|
+
}
|
|
179
|
+
.search-btn span{
|
|
180
|
+
color:var(--c-text-muted);
|
|
181
|
+
font-size:.95rem;
|
|
182
|
+
}
|
|
183
|
+
/* Hide search emoji on desktop */
|
|
184
|
+
.search-btn .search-icon {
|
|
185
|
+
display:none;
|
|
186
|
+
}
|
|
187
|
+
kbd{
|
|
188
|
+
font-size:.75rem;
|
|
189
|
+
color:var(--c-text-muted);
|
|
190
|
+
border:1px solid var(--c-border);
|
|
191
|
+
background:var(--c-bg);
|
|
192
|
+
padding:.2rem .4rem;
|
|
193
|
+
border-radius:var(--c-radius-sm);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Mobile: hide Command-K text and search text, show only icon */
|
|
197
|
+
@media (max-width: 768px) {
|
|
198
|
+
.search-btn kbd,
|
|
199
|
+
.search-btn .search-text {
|
|
200
|
+
display:none;
|
|
201
|
+
}
|
|
202
|
+
.search-btn .search-icon {
|
|
203
|
+
display:block;
|
|
204
|
+
font-size:1.1rem;
|
|
205
|
+
}
|
|
206
|
+
.search-btn {
|
|
207
|
+
padding:.6rem;
|
|
208
|
+
min-width:2.5rem;
|
|
209
|
+
justify-content:center;
|
|
210
|
+
}
|
|
211
|
+
.avatar {
|
|
212
|
+
width:2.2rem;
|
|
213
|
+
height:2.2rem;
|
|
214
|
+
}
|
|
215
|
+
.controls {
|
|
216
|
+
gap:.5rem;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
</style>
|
|
220
|
+
|
|
221
|
+
<script is:inline>
|
|
222
|
+
// Theme toggle
|
|
223
|
+
(function initTheme(){
|
|
224
|
+
const toggle = document.getElementById('theme-toggle');
|
|
225
|
+
const root = document.documentElement;
|
|
226
|
+
|
|
227
|
+
// Get saved theme or default to system preference
|
|
228
|
+
const savedTheme = localStorage.getItem('commune-theme');
|
|
229
|
+
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
230
|
+
const initialTheme = savedTheme || (systemPrefersDark ? 'dark' : 'light');
|
|
231
|
+
|
|
232
|
+
root.setAttribute('data-theme', initialTheme);
|
|
233
|
+
|
|
234
|
+
toggle?.addEventListener('click', () => {
|
|
235
|
+
const currentTheme = root.getAttribute('data-theme');
|
|
236
|
+
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
|
237
|
+
root.setAttribute('data-theme', newTheme);
|
|
238
|
+
localStorage.setItem('commune-theme', newTheme);
|
|
239
|
+
});
|
|
240
|
+
})();
|
|
241
|
+
|
|
242
|
+
// cmd/ctrl-k opens modal
|
|
243
|
+
addEventListener('keydown', (e) => {
|
|
244
|
+
const mac = navigator.platform.toUpperCase().includes('MAC');
|
|
245
|
+
if ((mac ? e.metaKey : e.ctrlKey) && e.key.toLowerCase() === 'k') {
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
dispatchEvent(new CustomEvent('commune:openSearch'));
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
</script>
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
<script is:inline>
|
|
2
|
+
// === HEADER STAR INITIALIZATION ===
|
|
3
|
+
// Adds a ⭐ star to the h1 title of starred notes with a clickable modal
|
|
4
|
+
|
|
5
|
+
(function() {
|
|
6
|
+
let backlinksData = null;
|
|
7
|
+
|
|
8
|
+
// Show the star modal
|
|
9
|
+
function showStarModal() {
|
|
10
|
+
const modal = document.getElementById('star-modal');
|
|
11
|
+
if (modal) {
|
|
12
|
+
modal.style.display = 'flex';
|
|
13
|
+
// Prevent body scroll when modal is open
|
|
14
|
+
document.body.style.overflow = 'hidden';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Hide the star modal
|
|
19
|
+
function hideStarModal() {
|
|
20
|
+
const modal = document.getElementById('star-modal');
|
|
21
|
+
if (modal) {
|
|
22
|
+
modal.style.display = 'none';
|
|
23
|
+
document.body.style.overflow = '';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Create the modal HTML (only once)
|
|
28
|
+
function createStarModal() {
|
|
29
|
+
if (document.getElementById('star-modal')) return; // Already exists
|
|
30
|
+
|
|
31
|
+
const modal = document.createElement('div');
|
|
32
|
+
modal.id = 'star-modal';
|
|
33
|
+
modal.className = 'star-modal';
|
|
34
|
+
modal.innerHTML = `
|
|
35
|
+
<div class="star-modal-backdrop"></div>
|
|
36
|
+
<div class="star-modal-content">
|
|
37
|
+
<button class="star-modal-close" aria-label="Close">×</button>
|
|
38
|
+
<div class="star-modal-body">
|
|
39
|
+
<div class="star-modal-icon">⭐</div>
|
|
40
|
+
<h2>Top 5%</h2>
|
|
41
|
+
<p>Other notes link here often. Shows this idea anchors your wiki.</p>
|
|
42
|
+
<p><a href="/notes/the-star/" class="star-link">More about <span class="star-emoji">⭐</span></a></p>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
document.body.appendChild(modal);
|
|
48
|
+
|
|
49
|
+
// Close on modal/backdrop click (but not on content)
|
|
50
|
+
modal.addEventListener('click', hideStarModal);
|
|
51
|
+
|
|
52
|
+
// Prevent clicks on modal content from closing modal
|
|
53
|
+
modal.querySelector('.star-modal-content').addEventListener('click', (e) => {
|
|
54
|
+
e.stopPropagation();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Close on X button click
|
|
58
|
+
modal.querySelector('.star-modal-close').addEventListener('click', (e) => {
|
|
59
|
+
e.stopPropagation(); // Prevent double-close
|
|
60
|
+
hideStarModal();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Close on Escape key
|
|
64
|
+
document.addEventListener('keydown', (e) => {
|
|
65
|
+
if (e.key === 'Escape' && modal.style.display === 'flex') {
|
|
66
|
+
hideStarModal();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function initializeHeaderStar(scope = document) {
|
|
72
|
+
try {
|
|
73
|
+
// Fetch backlinks data if not already loaded
|
|
74
|
+
if (!backlinksData) {
|
|
75
|
+
const res = await fetch('/backlinks.json');
|
|
76
|
+
if (res.ok) {
|
|
77
|
+
backlinksData = await res.json();
|
|
78
|
+
} else {
|
|
79
|
+
console.warn('Failed to load backlinks.json for header star');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Create modal (only once globally)
|
|
85
|
+
createStarModal();
|
|
86
|
+
|
|
87
|
+
// Find the current note's slug from the URL
|
|
88
|
+
const currentPath = window.location.pathname;
|
|
89
|
+
const normalizedPath = currentPath.endsWith('/') ? currentPath : currentPath + '/';
|
|
90
|
+
|
|
91
|
+
// Check if current note is starred
|
|
92
|
+
const note = backlinksData[normalizedPath];
|
|
93
|
+
|
|
94
|
+
if (note?.isStarred) {
|
|
95
|
+
// Find all h1 elements within the scope
|
|
96
|
+
const h1s = scope.querySelectorAll('.prose h1');
|
|
97
|
+
|
|
98
|
+
h1s.forEach(h1 => {
|
|
99
|
+
// Check if star isn't already there
|
|
100
|
+
if (!h1.querySelector('.star-indicator')) {
|
|
101
|
+
// Create wrapper to prevent line break between last word and star
|
|
102
|
+
const wrapper = document.createElement('span');
|
|
103
|
+
wrapper.style.whiteSpace = 'nowrap';
|
|
104
|
+
|
|
105
|
+
// Create star element (inline, clickable)
|
|
106
|
+
const star = document.createElement('span');
|
|
107
|
+
star.className = 'star-indicator';
|
|
108
|
+
star.innerHTML = ' ⭐';
|
|
109
|
+
star.setAttribute('aria-label', 'Top 5% most linked - click to learn more');
|
|
110
|
+
star.setAttribute('role', 'button');
|
|
111
|
+
star.setAttribute('tabindex', '0');
|
|
112
|
+
|
|
113
|
+
// Click handler to open modal
|
|
114
|
+
star.addEventListener('click', (e) => {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
showStarModal();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Keyboard support
|
|
120
|
+
star.addEventListener('keydown', (e) => {
|
|
121
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
showStarModal();
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Get the h1's text content
|
|
128
|
+
const textContent = h1.textContent || '';
|
|
129
|
+
const words = textContent.trim().split(/\s+/);
|
|
130
|
+
|
|
131
|
+
// If there's more than one word, wrap the last word + star
|
|
132
|
+
if (words.length > 1) {
|
|
133
|
+
const lastWord = words.pop();
|
|
134
|
+
const restOfText = words.join(' ');
|
|
135
|
+
|
|
136
|
+
h1.textContent = restOfText + ' ';
|
|
137
|
+
wrapper.textContent = lastWord;
|
|
138
|
+
wrapper.appendChild(star);
|
|
139
|
+
h1.appendChild(wrapper);
|
|
140
|
+
} else {
|
|
141
|
+
// Just one word, append star directly with nowrap
|
|
142
|
+
wrapper.textContent = textContent;
|
|
143
|
+
wrapper.appendChild(star);
|
|
144
|
+
h1.textContent = '';
|
|
145
|
+
h1.appendChild(wrapper);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('Error initializing header star:', error);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Make functions globally available
|
|
156
|
+
window.initializeHeaderStar = initializeHeaderStar;
|
|
157
|
+
window.showStarModal = showStarModal;
|
|
158
|
+
|
|
159
|
+
// Auto-initialize on DOM ready
|
|
160
|
+
if (document.readyState === 'loading') {
|
|
161
|
+
document.addEventListener('DOMContentLoaded', () => initializeHeaderStar());
|
|
162
|
+
} else {
|
|
163
|
+
initializeHeaderStar();
|
|
164
|
+
}
|
|
165
|
+
})();
|
|
166
|
+
</script>
|
|
167
|
+
|
|
168
|
+
<style is:global>
|
|
169
|
+
/* Star indicator - inline with title (Skool-style) */
|
|
170
|
+
.star-indicator {
|
|
171
|
+
display: inline-block;
|
|
172
|
+
cursor: pointer;
|
|
173
|
+
font-size: 1em;
|
|
174
|
+
margin-left: 0.35em;
|
|
175
|
+
opacity: 0.9;
|
|
176
|
+
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
177
|
+
user-select: none;
|
|
178
|
+
white-space: nowrap;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.star-indicator:hover {
|
|
182
|
+
opacity: 1;
|
|
183
|
+
transform: scale(1.1);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.star-indicator:focus {
|
|
187
|
+
outline: 2px solid var(--c-accent);
|
|
188
|
+
outline-offset: 4px;
|
|
189
|
+
border-radius: 4px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Inline stars (in WikiLinks and backlinks) */
|
|
193
|
+
.star-indicator-inline {
|
|
194
|
+
display: inline-block;
|
|
195
|
+
cursor: pointer;
|
|
196
|
+
margin-left: 0.15em;
|
|
197
|
+
opacity: 0.9;
|
|
198
|
+
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
199
|
+
user-select: none;
|
|
200
|
+
text-decoration: none !important;
|
|
201
|
+
border-bottom: none !important;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.star-indicator-inline:hover {
|
|
205
|
+
opacity: 1;
|
|
206
|
+
transform: scale(1.1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.star-indicator-inline:focus {
|
|
210
|
+
outline: 2px solid var(--c-accent);
|
|
211
|
+
outline-offset: 4px;
|
|
212
|
+
border-radius: 4px;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* Modal styles */
|
|
216
|
+
.star-modal {
|
|
217
|
+
display: none; /* Hidden by default, shown via JS */
|
|
218
|
+
position: fixed;
|
|
219
|
+
top: 0;
|
|
220
|
+
left: 0;
|
|
221
|
+
right: 0;
|
|
222
|
+
bottom: 0;
|
|
223
|
+
z-index: 9999;
|
|
224
|
+
align-items: center;
|
|
225
|
+
justify-content: center;
|
|
226
|
+
animation: fadeIn 0.2s ease;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
@keyframes fadeIn {
|
|
230
|
+
from { opacity: 0; }
|
|
231
|
+
to { opacity: 1; }
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.star-modal-backdrop {
|
|
235
|
+
position: absolute;
|
|
236
|
+
top: 0;
|
|
237
|
+
left: 0;
|
|
238
|
+
right: 0;
|
|
239
|
+
bottom: 0;
|
|
240
|
+
background: rgba(0, 0, 0, 0.75);
|
|
241
|
+
backdrop-filter: blur(4px);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.star-modal-content {
|
|
245
|
+
position: relative;
|
|
246
|
+
background: var(--c-bg);
|
|
247
|
+
border-radius: var(--c-radius-lg);
|
|
248
|
+
max-width: 540px;
|
|
249
|
+
width: 90%;
|
|
250
|
+
max-height: 85vh;
|
|
251
|
+
overflow-y: auto;
|
|
252
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
253
|
+
animation: slideUp 0.3s cubic-bezier(0.22, 1, 0.36, 1);
|
|
254
|
+
border: 1px solid var(--c-border);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
@keyframes slideUp {
|
|
258
|
+
from {
|
|
259
|
+
transform: translateY(20px);
|
|
260
|
+
opacity: 0;
|
|
261
|
+
}
|
|
262
|
+
to {
|
|
263
|
+
transform: translateY(0);
|
|
264
|
+
opacity: 1;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.star-modal-close {
|
|
269
|
+
position: absolute;
|
|
270
|
+
top: 1rem;
|
|
271
|
+
right: 1rem;
|
|
272
|
+
width: 32px;
|
|
273
|
+
height: 32px;
|
|
274
|
+
background: var(--c-bg-soft);
|
|
275
|
+
border: 1px solid var(--c-border);
|
|
276
|
+
border-radius: 50%;
|
|
277
|
+
display: flex;
|
|
278
|
+
align-items: center;
|
|
279
|
+
justify-content: center;
|
|
280
|
+
cursor: pointer;
|
|
281
|
+
font-size: 1.5rem;
|
|
282
|
+
line-height: 1;
|
|
283
|
+
color: var(--c-text-muted);
|
|
284
|
+
transition: all 0.2s ease;
|
|
285
|
+
padding: 0;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.star-modal-close:hover {
|
|
289
|
+
background: var(--c-bg-muted);
|
|
290
|
+
color: var(--c-text);
|
|
291
|
+
transform: rotate(90deg);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.star-modal-body {
|
|
295
|
+
padding: 2.5rem 2rem 2rem;
|
|
296
|
+
text-align: center;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.star-modal-icon {
|
|
300
|
+
font-size: 3.5rem;
|
|
301
|
+
margin-bottom: 0.75rem;
|
|
302
|
+
animation: starPulse 2s ease-in-out infinite;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
@keyframes starPulse {
|
|
306
|
+
0%, 100% { transform: scale(1); }
|
|
307
|
+
50% { transform: scale(1.1); }
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.star-modal-body h2 {
|
|
311
|
+
font-size: 1.5rem;
|
|
312
|
+
font-weight: 700;
|
|
313
|
+
margin-bottom: 0.75rem;
|
|
314
|
+
color: var(--c-text);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.star-modal-body p {
|
|
318
|
+
font-size: 1rem;
|
|
319
|
+
line-height: 1.5;
|
|
320
|
+
color: var(--c-text-accent);
|
|
321
|
+
margin-bottom: 0.75rem;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.star-modal-body p:last-child {
|
|
325
|
+
margin-bottom: 0;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.star-modal-body strong {
|
|
329
|
+
color: var(--c-accent);
|
|
330
|
+
font-weight: 600;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.star-modal-body em {
|
|
334
|
+
font-style: italic;
|
|
335
|
+
color: var(--c-text);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.star-link {
|
|
339
|
+
color: var(--c-accent);
|
|
340
|
+
text-decoration: underline;
|
|
341
|
+
text-decoration-thickness: 1px;
|
|
342
|
+
text-underline-offset: 2px;
|
|
343
|
+
transition: opacity 0.2s ease;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.star-link:hover {
|
|
347
|
+
opacity: 0.8;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.star-link .star-emoji {
|
|
351
|
+
text-decoration: none;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/* Mobile adjustments */
|
|
355
|
+
@media (max-width: 1023px) {
|
|
356
|
+
.star-modal-content {
|
|
357
|
+
width: 95%;
|
|
358
|
+
max-height: 90vh;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.star-modal-body {
|
|
362
|
+
padding: 2rem 1.5rem 1.5rem;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.star-modal-body h2 {
|
|
366
|
+
font-size: 1.35rem;
|
|
367
|
+
margin-bottom: 0.5rem;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.star-modal-icon {
|
|
371
|
+
font-size: 2.5rem;
|
|
372
|
+
margin-bottom: 0.5rem;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.star-modal-body p {
|
|
376
|
+
font-size: 0.95rem;
|
|
377
|
+
margin-bottom: 0.5rem;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
</style>
|