Skip to content

Commit 2ecb141

Browse files
committed
Update styling to be more consistent
1 parent 8ac2818 commit 2ecb141

File tree

2 files changed

+184
-2
lines changed

2 files changed

+184
-2
lines changed

pages/css/style.css

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,57 @@ button {
308308
margin-bottom: 10px;
309309
}
310310

311+
.shared-files-section {
312+
margin-bottom: 0px;
313+
}
314+
315+
.shared-files-header {
316+
color: #7431ff;
317+
font-size: 1.1rem;
318+
font-weight: 600;
319+
cursor: pointer;
320+
padding: 12px;
321+
background: rgba(116, 49, 255, 0.08);
322+
border: 1px solid rgba(116, 49, 255, 0.15);
323+
border-radius: 8px;
324+
display: flex;
325+
align-items: center;
326+
gap: 10px;
327+
user-select: none;
328+
transition: all 0.3s ease;
329+
}
330+
331+
.shared-files-header:hover {
332+
background: rgba(116, 49, 255, 0.15);
333+
border-color: rgba(116, 49, 255, 0.3);
334+
}
335+
336+
.shared-files-toggle {
337+
display: inline-block;
338+
transition: transform 0.3s ease;
339+
}
340+
341+
.shared-files-toggle.expanded {
342+
transform: rotate(180deg);
343+
}
344+
345+
.shared-files-list {
346+
display: none;
347+
flex-direction: column;
348+
gap: 10px;
349+
margin-top: 10px;
350+
}
351+
352+
.shared-files-list.visible {
353+
display: flex;
354+
}
355+
356+
.shared-files-separator {
357+
height: 1px;
358+
background: rgba(116, 49, 255, 0.2);
359+
margin: 20px 0;
360+
}
361+
311362
/* === Spinner === */
312363
.spinner {
313364
display: inline-block;

pages/js/files.js

Lines changed: 133 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class FileVault {
88
this.username = username;
99
this.password = password;
1010
this.index = null;
11+
this.sharedIndex = null;
1112
this.currentPath = '';
1213
this.repoURL = `https://raw.githubusercontent.com/${username}/.zephyrus/master`;
1314
}
@@ -29,6 +30,10 @@ class FileVault {
2930
const jsonString = new TextDecoder().decode(decryptedBuffer);
3031

3132
this.index = JSON.parse(jsonString);
33+
34+
// Also try to load the shared index
35+
await this.loadSharedIndex();
36+
3237
return this.index;
3338
} catch (error) {
3439
if (error instanceof SyntaxError) {
@@ -38,6 +43,62 @@ class FileVault {
3843
}
3944
}
4045

46+
/**
47+
* Fetch and decrypt the shared index
48+
*/
49+
async loadSharedIndex() {
50+
try {
51+
const sharedIndexUrl = `${this.repoURL}/shared/.config/index`;
52+
const response = await fetch(sharedIndexUrl);
53+
54+
if (!response.ok) {
55+
// Shared index might not exist if no files have been shared
56+
console.log('No shared index found');
57+
this.sharedIndex = null;
58+
return;
59+
}
60+
61+
const encryptedBuffer = await response.arrayBuffer();
62+
const decryptedBuffer = await CRYPTO.decryptWithPassword(encryptedBuffer, this.password);
63+
const jsonString = new TextDecoder().decode(decryptedBuffer);
64+
65+
this.sharedIndex = JSON.parse(jsonString);
66+
console.log('Shared index loaded:', this.sharedIndex);
67+
} catch (error) {
68+
console.warn('Failed to load shared index:', error);
69+
this.sharedIndex = null;
70+
}
71+
}
72+
73+
/**
74+
* Get all shared files
75+
*/
76+
getSharedFiles() {
77+
if (!this.sharedIndex || !this.sharedIndex.files) {
78+
return [];
79+
}
80+
81+
const entries = Object.values(this.sharedIndex.files);
82+
return entries.sort((a, b) => {
83+
const dateA = new Date(a.shared_at || a.SharedAt || 0);
84+
const dateB = new Date(b.shared_at || b.SharedAt || 0);
85+
return dateB - dateA; // Most recent first
86+
});
87+
}
88+
89+
/**
90+
* Generate share link from shared entry
91+
*/
92+
generateShareLink(sharedEntry) {
93+
const filename = sharedEntry.name || sharedEntry.Name || '';
94+
const encodedFilename = btoa(filename);
95+
const reference = sharedEntry.reference || sharedEntry.Reference;
96+
const password = sharedEntry.password || sharedEntry.Password;
97+
98+
// Format: username:reference:password:base64filename
99+
return `${this.username}:${reference}:${password}:${encodedFilename}`;
100+
}
101+
41102
/**
42103
* Get the current directory contents
43104
*/
@@ -361,8 +422,66 @@ class FileBrowserUI {
361422
const fileList = document.getElementById('fileList');
362423
fileList.innerHTML = '';
363424

364-
if (items.length === 0) {
365-
fileList.innerHTML = `
425+
// If in root, show "Shared Files" section first
426+
if (!this.vault.currentPath && this.vault.sharedIndex) {
427+
const sharedFiles = this.vault.getSharedFiles();
428+
if (sharedFiles.length > 0) {
429+
const sharedSection = document.createElement('div');
430+
sharedSection.className = 'shared-files-section';
431+
432+
const header = document.createElement('div');
433+
header.className = 'shared-files-header';
434+
header.innerHTML = `<span class="shared-files-toggle">▼</span> 📤 Your Shared Files (${sharedFiles.length})`;
435+
436+
const listContainer = document.createElement('div');
437+
listContainer.className = 'shared-files-list';
438+
listContainer.id = 'sharedFilesList';
439+
440+
// Add shared files to list
441+
for (const shared of sharedFiles) {
442+
const shareLink = this.vault.generateShareLink(shared);
443+
// Build correct URL: from /pages/files/ to /pages/shared/#hash
444+
const basePath = window.location.pathname.replace('/files/', '/shared/');
445+
const shareUrl = `${basePath}#${shareLink}`;
446+
447+
const element = document.createElement('div');
448+
element.className = 'file-item';
449+
element.innerHTML = `
450+
<div class="file-icon">📤</div>
451+
<div class="file-info">
452+
<div class="file-name">${this.escapeHtml(shared.name || shared.Name)}</div>
453+
<div class="file-path">${this.escapeHtml(shared.original_path || shared.OriginalPath)}</div>
454+
</div>
455+
<div class="file-actions">
456+
<button class="btn-secondary btn-small" onclick="fileBrowser.copyShareLink('${this.escapeAttr(shareUrl)}')">
457+
🔗 Copy Link
458+
</button>
459+
</div>
460+
`;
461+
listContainer.appendChild(element);
462+
}
463+
464+
// Add separator after shared files
465+
const separator = document.createElement('div');
466+
separator.className = 'shared-files-separator';
467+
listContainer.appendChild(separator);
468+
469+
// Toggle handler
470+
header.addEventListener('click', () => {
471+
const toggle = header.querySelector('.shared-files-toggle');
472+
listContainer.classList.toggle('visible');
473+
toggle.classList.toggle('expanded');
474+
});
475+
476+
sharedSection.appendChild(header);
477+
sharedSection.appendChild(listContainer);
478+
fileList.appendChild(sharedSection);
479+
}
480+
}
481+
482+
// Show files and folders
483+
if (items.length === 0 && (!this.vault.currentPath || !this.vault.sharedIndex)) {
484+
fileList.innerHTML += `
366485
<div class="empty-state">
367486
<div class="empty-icon">📁</div>
368487
<div class="empty-text">This directory is empty</div>
@@ -438,6 +557,18 @@ class FileBrowserUI {
438557
}
439558
}
440559

560+
/**
561+
* Copy share link to clipboard
562+
*/
563+
copyShareLink(shareUrl) {
564+
navigator.clipboard.writeText(shareUrl).then(() => {
565+
this.showSuccess('Share link copied to clipboard!');
566+
}).catch(err => {
567+
console.error('Failed to copy link:', err);
568+
this.showError('Failed to copy link');
569+
});
570+
}
571+
441572
/**
442573
* Download and display a file
443574
*/

0 commit comments

Comments
 (0)