From 02eaac783fa1d0b3f1eff777c4bea930aa5fdc92 Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Sat, 15 Nov 2025 21:52:53 -0300 Subject: [PATCH] feat(editor, settings): refactor state handling and enhance validation Refactored editor.page.html to use a Vue-style `data()` function for reactive state, adding a new `content` property and cleaning up redundant inline styles. Updated profile-form.html to replace single `error` handling with field-specific `errors.` bindings, improving form validation clarity and user feedback. --- web/app/editor/editor.page.html | 30 ++-- web/app/player/player.page.html | 39 +++++ web/app/settings/profile-form.html | 40 ++++-- web/app/settings/style.css | 18 +++ web/desktop/dashboard/dashboard.css | 4 + web/desktop/dashboard/dashboard.html | 14 +- web/desktop/dashboard/dashboard.js | 16 ++- web/desktop/drive/drive.css | 1 + web/desktop/editor/editor.html | 142 ++++++++----------- web/desktop/index.html | 8 ++ web/desktop/js/layout.js | 30 +++- web/desktop/mail/mail.css | 1 + web/desktop/news/news.html | 11 -- web/desktop/paper/paper.html | 124 +++++++--------- web/desktop/player/player.html | 35 ++--- web/desktop/player/player.js | 114 +++++++-------- web/desktop/settings/settings.html | 116 +++++++-------- web/desktop/{tablesv2 => tables}/tables.css | 0 web/desktop/{tablesv2 => tables}/tables.html | 12 -- web/desktop/{tablesv2 => tables}/tables.js | 0 web/desktop/tasks/tasks.css | 1 + 21 files changed, 391 insertions(+), 365 deletions(-) create mode 100644 web/app/player/player.page.html create mode 100644 web/app/settings/style.css create mode 100644 web/desktop/drive/drive.css create mode 100644 web/desktop/mail/mail.css rename web/desktop/{tablesv2 => tables}/tables.css (100%) rename web/desktop/{tablesv2 => tables}/tables.html (85%) rename web/desktop/{tablesv2 => tables}/tables.js (100%) create mode 100644 web/desktop/tasks/tasks.css diff --git a/web/app/editor/editor.page.html b/web/app/editor/editor.page.html index 7bd99a0b..3736ecb8 100644 --- a/web/app/editor/editor.page.html +++ b/web/app/editor/editor.page.html @@ -186,16 +186,22 @@ import './style.css'; export default { // Reactive state - fileName: 'Document 1', - fontSize: '12', - fontFamily: 'Calibri', - textColor: '#000000', - highlightColor: '#ffff00', - activeTab: 'home', - zoom: 100, - pages: [1], - editor: null, - fileInputRef: null, + data() { + return { + fileName: 'Document 1', + fontSize: '12', + fontFamily: 'Calibri', + textColor: '#000000', + highlightColor: '#ffff00', + activeTab: 'home', + zoom: 100, + pages: [1], + editor: null, + fileInputRef: null, + content: '', + activeTab: 'home' + } + }, // Lifecycle async mounted() { @@ -334,7 +340,3 @@ export default { }, }; - - diff --git a/web/app/player/player.page.html b/web/app/player/player.page.html new file mode 100644 index 00000000..c902a3c7 --- /dev/null +++ b/web/app/player/player.page.html @@ -0,0 +1,39 @@ + + + + diff --git a/web/app/settings/profile-form.html b/web/app/settings/profile-form.html index 395de3d4..706dbfa1 100644 --- a/web/app/settings/profile-form.html +++ b/web/app/settings/profile-form.html @@ -4,10 +4,10 @@
- - {error &&

{error.message}

} + {errors.username &&

{errors.username.message}

}

This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.

@@ -18,10 +18,10 @@
- {error &&

{error.message}

} + {errors.email &&

{errors.email.message}

}

You can manage verified email addresses in your email settings.

@@ -31,11 +31,11 @@
- - {error &&

{error.message}

} + {errors.bio &&

{errors.bio.message}

}

You can @mention other users and organizations to link to them.

@@ -58,10 +58,18 @@ import './style.css'; export default { // Reactive state - username: '', - email: '', - bio: '', - error: null, + data() { + return { + username: '', + email: '', + bio: '', + errors: { + username: null, + email: null, + bio: null + } + } + }, // Validation schema schema: z.object({ @@ -77,10 +85,20 @@ export default { email: this.email, bio: this.bio }); + + // Clear previous errors + this.errors = { + username: null, + email: null, + bio: null + }; + if (result.success) { callback(result.data); } else { - this.error = result.error.errors[0]; + result.error.errors.forEach(err => { + this.errors[err.path[0]] = err; + }); } }, diff --git a/web/app/settings/style.css b/web/app/settings/style.css new file mode 100644 index 00000000..b833d162 --- /dev/null +++ b/web/app/settings/style.css @@ -0,0 +1,18 @@ +/* Settings page styles */ +.settings-container { + padding: 20px; + max-width: 1200px; + margin: 0 auto; +} + +.settings-section { + margin-bottom: 30px; + border-bottom: 1px solid #eee; + padding-bottom: 20px; +} + +.settings-title { + font-size: 1.5rem; + margin-bottom: 15px; + color: #333; +} diff --git a/web/desktop/dashboard/dashboard.css b/web/desktop/dashboard/dashboard.css index 0ea2d223..fc6dd156 100644 --- a/web/desktop/dashboard/dashboard.css +++ b/web/desktop/dashboard/dashboard.css @@ -71,3 +71,7 @@ .download-btn:hover { background: #2563eb; } + +.dashboard-section { + padding: 1rem; +} diff --git a/web/desktop/dashboard/dashboard.html b/web/desktop/dashboard/dashboard.html index afa7c2d1..a882218e 100644 --- a/web/desktop/dashboard/dashboard.html +++ b/web/desktop/dashboard/dashboard.html @@ -1,16 +1,8 @@ - - - - Dashboard - - - -
-

Dashboard

+

1Dashboard

@@ -36,6 +28,4 @@ - - - + \ No newline at end of file diff --git a/web/desktop/dashboard/dashboard.js b/web/desktop/dashboard/dashboard.js index 4c875443..dac46de8 100644 --- a/web/desktop/dashboard/dashboard.js +++ b/web/desktop/dashboard/dashboard.js @@ -21,10 +21,18 @@ document.addEventListener('DOMContentLoaded', () => { ] }; - // Initialize dashboard + // Initialize dashboard safely function init() { - renderCards(); - document.querySelector('.download-btn').addEventListener('click', handleDownload); + const ensure = setInterval(() => { + const main = document.querySelector('#main-content'); + const section = main && main.querySelector('.cards-grid'); + const btn = main && main.querySelector('.download-btn'); + if (section && btn) { + clearInterval(ensure); + renderCards(); + btn.addEventListener('click', handleDownload); + } + }, 100); } // Render dashboard cards @@ -54,5 +62,5 @@ document.addEventListener('DOMContentLoaded', () => { } // Initialize dashboard - init(); + document.addEventListener('DOMContentLoaded',()=>{init();}); }); diff --git a/web/desktop/drive/drive.css b/web/desktop/drive/drive.css new file mode 100644 index 00000000..b978c1b5 --- /dev/null +++ b/web/desktop/drive/drive.css @@ -0,0 +1 @@ +a {} \ No newline at end of file diff --git a/web/desktop/editor/editor.html b/web/desktop/editor/editor.html index 5e4c5655..d0cb589a 100644 --- a/web/desktop/editor/editor.html +++ b/web/desktop/editor/editor.html @@ -1,89 +1,73 @@ - - - - Editor - - - - - -
-
- -
- + +
+ + - -
- - -
+
+
+ + +
+
+ + +
- -
-
- - - -
- -
-
-
Format
-
- - - -
-
-
-
Alignment
-
- - - - -
+
+
+
Format
+
+ + +
-
- - -
-
-
-
-
Page 1
-
-
+
+
Alignment
+
+ + + +
- - -
-
Page of
-
- - - -
-
-
- - - + +
+
+
+
+
Page 1
+
+
+
+
+
+ + +
+
Page of
+
+ + + +
+
+
+
diff --git a/web/desktop/index.html b/web/desktop/index.html index 2c82f845..12c7119c 100644 --- a/web/desktop/index.html +++ b/web/desktop/index.html @@ -41,5 +41,13 @@ + + + + + + + + diff --git a/web/desktop/js/layout.js b/web/desktop/js/layout.js index e3804e9d..364dc8c8 100644 --- a/web/desktop/js/layout.js +++ b/web/desktop/js/layout.js @@ -7,7 +7,7 @@ const sections = { player: 'player/player.html', paper: 'paper/paper.html', settings: 'settings/settings.html', - tables: 'tablesv2/tables.html', + tables: 'tables/tables.html', news: 'news/news.html' }; @@ -21,8 +21,34 @@ async function switchSection(section) { const mainContent = document.getElementById('main-content'); try { - const html = await loadSectionHTML(sections[section]); + const htmlPath = sections[section]; + console.log('Loading section:', section, 'from', htmlPath); + const cssPath = + htmlPath.replace('.html', '.css'); + + // Remove any existing section CSS + document.querySelectorAll('link[data-section-css]').forEach(link => link.remove()); + + // Load CSS first + const cssLink = document.createElement('link'); + cssLink.rel = 'stylesheet'; + cssLink.href = cssPath; + cssLink.setAttribute('data-section-css', 'true'); + document.head.appendChild(cssLink); + + // First load HTML + const html = await loadSectionHTML(htmlPath); mainContent.innerHTML = html; + + // Then load JS after HTML is inserted + const jsPath = htmlPath.replace('.html', '.js'); + const existingScript = document.querySelector(`script[src="${jsPath}"]`); + if (!existingScript) { + const script = document.createElement('script'); + script.src = jsPath; + script.defer = true; + document.body.appendChild(script); + } window.history.pushState({}, '', `#${section}`); Alpine.initTree(mainContent); } catch (err) { diff --git a/web/desktop/mail/mail.css b/web/desktop/mail/mail.css new file mode 100644 index 00000000..b978c1b5 --- /dev/null +++ b/web/desktop/mail/mail.css @@ -0,0 +1 @@ +a {} \ No newline at end of file diff --git a/web/desktop/news/news.html b/web/desktop/news/news.html index 0a233878..97f1c47a 100644 --- a/web/desktop/news/news.html +++ b/web/desktop/news/news.html @@ -1,11 +1,3 @@ - - - - News - - - -
@@ -14,6 +6,3 @@
- - - diff --git a/web/desktop/paper/paper.html b/web/desktop/paper/paper.html index cbe773a2..16793bdd 100644 --- a/web/desktop/paper/paper.html +++ b/web/desktop/paper/paper.html @@ -1,77 +1,55 @@ - - - - Paper - - - - - -
-
-
- -
-
- Start writing your thoughts here... -
-
-
- - -
-
- - - - - -
- - - - - - -
- - - +
+
+
+ +
+
+ Start writing your thoughts here...
+ + +
+
+ + + + + +
+ + + + + + +
+ + + +
+
- - - +
\ No newline at end of file diff --git a/web/desktop/player/player.html b/web/desktop/player/player.html index e7c22084..d3d32241 100644 --- a/web/desktop/player/player.html +++ b/web/desktop/player/player.html @@ -1,26 +1,15 @@ - - - - Player - - - - -
-
-
-
- -
-
- - - 0:00 / 0:00 - -
+
+
+
+
+ +
+
+ + + 0:00 / 0:00 +
- - - +
\ No newline at end of file diff --git a/web/desktop/player/player.js b/web/desktop/player/player.js index c668bc40..aae00e38 100644 --- a/web/desktop/player/player.js +++ b/web/desktop/player/player.js @@ -1,61 +1,63 @@ // Player module JavaScript document.addEventListener('DOMContentLoaded', () => { - const playerContainer = document.querySelector('.player-container'); - const videoContainer = document.querySelector('.video-container'); - const playBtn = document.querySelector('.play-btn'); - const progressSlider = document.querySelector('.progress-slider'); - const volumeSlider = document.querySelector('.volume-slider'); - const timeDisplay = document.querySelector('.time-display'); - - // Create video element - const video = document.createElement('video'); - video.src = ''; // Will be set when loading media - video.controls = false; - videoContainer.appendChild(video); - - // Play/Pause toggle - playBtn.addEventListener('click', () => { - if (video.paused) { - video.play(); - playBtn.textContent = 'Pause'; - } else { - video.pause(); - playBtn.textContent = 'Play'; + const ready = setInterval(() => { + const container = document.querySelector('.player-container'); + if (!container) return; + clearInterval(ready); + const videoContainer = document.querySelector('.video-container'); + const playBtn = document.querySelector('.play-btn'); + const progressSlider = document.querySelector('.progress-slider'); + const volumeSlider = document.querySelector('.volume-slider'); + const timeDisplay = document.querySelector('.time-display'); + const ensure = setInterval(() => { + const container = document.querySelector('.video-container'); + if (container) { + clearInterval(ensure); + const video = document.createElement('video'); + video.src = ''; + video.controls = false; + container.appendChild(video); + setupControls(video); + } + }, 50); + function setupControls(video) { + const playBtn = document.querySelector('.play-btn'); + const progressSlider = document.querySelector('.progress-slider'); + const volumeSlider = document.querySelector('.volume-slider'); + const timeDisplay = document.querySelector('.time-display'); + playBtn.addEventListener('click', () => { + if (video.paused) { + video.play(); + playBtn.textContent = 'Pause'; + } else { + video.pause(); + playBtn.textContent = 'Play'; + } + }); + video.addEventListener('timeupdate', () => { + const progress = (video.currentTime / video.duration) * 100; + progressSlider.value = progress || 0; + updateTimeDisplay(video, timeDisplay); + }); + progressSlider.addEventListener('input', () => { + const seekTime = (progressSlider.value / 100) * video.duration; + video.currentTime = seekTime; + }); + volumeSlider.addEventListener('input', () => { + video.volume = volumeSlider.value / 100; + }); + window.loadMedia = (src) => { + video.src = src; + video.load(); + }; + } + function updateTimeDisplay(video, display) { + const formatTime = (seconds) => { + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins}:${secs < 10 ? '0' : ''}${secs}`; + }; + display.textContent = `${formatTime(video.currentTime)} / ${formatTime(video.duration)}`; } }); - - // Update progress slider - video.addEventListener('timeupdate', () => { - const progress = (video.currentTime / video.duration) * 100; - progressSlider.value = progress || 0; - updateTimeDisplay(); - }); - - // Seek video - progressSlider.addEventListener('input', () => { - const seekTime = (progressSlider.value / 100) * video.duration; - video.currentTime = seekTime; - }); - - // Volume control - volumeSlider.addEventListener('input', () => { - video.volume = volumeSlider.value / 100; - }); - - // Format time display - function updateTimeDisplay() { - const formatTime = (seconds) => { - const mins = Math.floor(seconds / 60); - const secs = Math.floor(seconds % 60); - return `${mins}:${secs < 10 ? '0' : ''}${secs}`; - }; - - timeDisplay.textContent = `${formatTime(video.currentTime)} / ${formatTime(video.duration)}`; - } - - // Load media (to be called externally) - window.loadMedia = (src) => { - video.src = src; - video.load(); - }; }); diff --git a/web/desktop/settings/settings.html b/web/desktop/settings/settings.html index 37f68536..a98a404e 100644 --- a/web/desktop/settings/settings.html +++ b/web/desktop/settings/settings.html @@ -1,74 +1,54 @@ - - - - Settings - - - - - -
-
-
-
-

Profile

-

+
+
+
+
+

Profile

+

+
+
+ +
+ +
+ + + +

+ This is your public display name. It can be your real name or a pseudonym. +

-
- -
- -
- - - -

- This is your public display name. It can be your real name or a pseudonym. -

-
- -
- - - -

- You can manage verified email addresses in your email settings. -

-
- - -
- - - -

- You can @mention other users and organizations to link to them. -

-
- - + +
+ + + +

+ You can manage verified email addresses in your email settings. +

+ + +
+ + + +

+ You can @mention other users and organizations to link to them. +

+
+ +
- - - +
\ No newline at end of file diff --git a/web/desktop/tablesv2/tables.css b/web/desktop/tables/tables.css similarity index 100% rename from web/desktop/tablesv2/tables.css rename to web/desktop/tables/tables.css diff --git a/web/desktop/tablesv2/tables.html b/web/desktop/tables/tables.html similarity index 85% rename from web/desktop/tablesv2/tables.html rename to web/desktop/tables/tables.html index 2d4deeb5..7591e213 100644 --- a/web/desktop/tablesv2/tables.html +++ b/web/desktop/tables/tables.html @@ -1,12 +1,3 @@ - - - - Tables - - - - -
@@ -62,6 +53,3 @@
- - - diff --git a/web/desktop/tablesv2/tables.js b/web/desktop/tables/tables.js similarity index 100% rename from web/desktop/tablesv2/tables.js rename to web/desktop/tables/tables.js diff --git a/web/desktop/tasks/tasks.css b/web/desktop/tasks/tasks.css new file mode 100644 index 00000000..b978c1b5 --- /dev/null +++ b/web/desktop/tasks/tasks.css @@ -0,0 +1 @@ +a {} \ No newline at end of file