botui/ui/suite/slides/slides.html
Rodrigo Rodriguez (Pragmatismo) d8e52bf330 feat(auth): Add user profile loading and auth state management
- Add JavaScript to load user profile from /api/auth/me endpoint
- Save access_token to localStorage/sessionStorage on login
- Update user menu to show actual user name and email
- Toggle Sign in/Sign out based on authentication state
- Add IDs to user menu elements for dynamic updates
2026-01-06 22:57:00 -03:00

1142 lines
50 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GB Slides</title>
<link rel="stylesheet" href="slides.css" />
</head>
<body>
<div class="slides-container">
<!-- Sidebar: Slide Thumbnails -->
<aside class="slides-sidebar" id="slides-sidebar">
<div class="sidebar-header">
<h2>Slides</h2>
<button
class="btn-icon"
onclick="toggleSidebar()"
title="Toggle Sidebar"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</button>
</div>
<div class="sidebar-search">
<input
type="text"
placeholder="Search presentations..."
id="search-input"
oninput="searchPresentations(this.value)"
/>
<svg
class="search-icon"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
</div>
<div class="slide-thumbnails" id="slide-thumbnails">
<!-- Thumbnails rendered dynamically -->
</div>
<div class="sidebar-actions">
<button class="btn-add-slide" onclick="addSlide()">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
<span>Add Slide</span>
</button>
</div>
</aside>
<!-- Main Content Area -->
<main class="slides-main">
<!-- Toolbar -->
<div class="slides-toolbar">
<div class="toolbar-left">
<button
class="btn-icon"
onclick="toggleSidebar()"
title="Toggle Sidebar"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="2"
ry="2"
></rect>
<line x1="9" y1="3" x2="9" y2="21"></line>
</svg>
</button>
<input
type="text"
class="presentation-name-input"
id="presentation-name"
value="Untitled Presentation"
onchange="renamePresentation(this.value)"
/>
</div>
<div class="toolbar-center">
<!-- Insert Tools -->
<div class="toolbar-group">
<button
class="btn-icon"
onclick="addTextBox()"
title="Add Text"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<polyline
points="4 7 4 4 20 4 20 7"
></polyline>
<line x1="9" y1="20" x2="15" y2="20"></line>
<line x1="12" y1="4" x2="12" y2="20"></line>
</svg>
</button>
<button
class="btn-icon"
onclick="showImageModal()"
title="Add Image"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="2"
ry="2"
></rect>
<circle cx="8.5" cy="8.5" r="1.5"></circle>
<polyline
points="21 15 16 10 5 21"
></polyline>
</svg>
</button>
<button
class="btn-icon"
onclick="showShapeModal()"
title="Add Shape"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="2"
></rect>
</svg>
</button>
<button
class="btn-icon"
onclick="showChartModal()"
title="Add Chart"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line
x1="18"
y1="20"
x2="18"
y2="10"
></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
</button>
<button
class="btn-icon"
onclick="addTable()"
title="Add Table"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="2"
></rect>
<line x1="3" y1="9" x2="21" y2="9"></line>
<line x1="3" y1="15" x2="21" y2="15"></line>
<line x1="9" y1="3" x2="9" y2="21"></line>
<line x1="15" y1="3" x2="15" y2="21"></line>
</svg>
</button>
</div>
<span class="toolbar-divider"></span>
<!-- Text Formatting -->
<div class="toolbar-group">
<select
class="toolbar-select font-family"
id="font-family"
onchange="setFontFamily(this.value)"
>
<option value="Inter">Inter</option>
<option value="Arial">Arial</option>
<option value="Helvetica">Helvetica</option>
<option value="Georgia">Georgia</option>
<option value="Times New Roman">
Times New Roman
</option>
<option value="Courier New">Courier New</option>
</select>
<select
class="toolbar-select font-size"
id="font-size"
onchange="setFontSize(this.value)"
>
<option value="12">12</option>
<option value="14">14</option>
<option value="16">16</option>
<option value="18">18</option>
<option value="20">20</option>
<option value="24" selected>24</option>
<option value="28">28</option>
<option value="32">32</option>
<option value="36">36</option>
<option value="48">48</option>
<option value="64">64</option>
<option value="72">72</option>
</select>
</div>
<span class="toolbar-divider"></span>
<!-- Text Style -->
<div class="toolbar-group">
<button
class="btn-icon"
id="btn-bold"
onclick="toggleBold()"
title="Bold (Ctrl+B)"
>
<strong>B</strong>
</button>
<button
class="btn-icon"
id="btn-italic"
onclick="toggleItalic()"
title="Italic (Ctrl+I)"
>
<em>I</em>
</button>
<button
class="btn-icon"
id="btn-underline"
onclick="toggleUnderline()"
title="Underline (Ctrl+U)"
>
<u>U</u>
</button>
</div>
<span class="toolbar-divider"></span>
<!-- Colors -->
<div class="toolbar-group">
<div class="color-btn" title="Text Color">
<span style="font-weight: bold">A</span>
<span
class="color-indicator"
id="text-color-indicator"
style="background: #000000"
></span>
<input
type="color"
class="color-input"
id="text-color"
value="#000000"
onchange="setTextColor(this.value)"
/>
</div>
<div class="color-btn" title="Fill Color">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="currentColor"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="2"
></rect>
</svg>
<span
class="color-indicator"
id="fill-color-indicator"
style="background: #3b82f6"
></span>
<input
type="color"
class="color-input"
id="fill-color"
value="#3b82f6"
onchange="setFillColor(this.value)"
/>
</div>
<div class="color-btn" title="Stroke Color">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="3"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="2"
></rect>
</svg>
<span
class="color-indicator"
id="stroke-color-indicator"
style="background: #1e293b"
></span>
<input
type="color"
class="color-input"
id="stroke-color"
value="#1e293b"
onchange="setStrokeColor(this.value)"
/>
</div>
</div>
<span class="toolbar-divider"></span>
<!-- Alignment -->
<div class="toolbar-group">
<button
class="btn-icon"
onclick="setTextAlign('left')"
title="Align Left"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="17" y1="10" x2="3" y2="10"></line>
<line x1="21" y1="6" x2="3" y2="6"></line>
<line x1="21" y1="14" x2="3" y2="14"></line>
<line x1="17" y1="18" x2="3" y2="18"></line>
</svg>
</button>
<button
class="btn-icon"
onclick="setTextAlign('center')"
title="Align Center"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="10" x2="6" y2="10"></line>
<line x1="21" y1="6" x2="3" y2="6"></line>
<line x1="21" y1="14" x2="3" y2="14"></line>
<line x1="18" y1="18" x2="6" y2="18"></line>
</svg>
</button>
<button
class="btn-icon"
onclick="setTextAlign('right')"
title="Align Right"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="21" y1="10" x2="7" y2="10"></line>
<line x1="21" y1="6" x2="3" y2="6"></line>
<line x1="21" y1="14" x2="3" y2="14"></line>
<line x1="21" y1="18" x2="7" y2="18"></line>
</svg>
</button>
</div>
<span class="toolbar-divider"></span>
<!-- Layer Order -->
<div class="toolbar-group">
<button
class="btn-icon"
onclick="bringForward()"
title="Bring Forward"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect
x="8"
y="8"
width="13"
height="13"
rx="2"
></rect>
<rect
x="3"
y="3"
width="13"
height="13"
rx="2"
fill="currentColor"
opacity="0.3"
></rect>
</svg>
</button>
<button
class="btn-icon"
onclick="sendBackward()"
title="Send Backward"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect
x="3"
y="3"
width="13"
height="13"
rx="2"
></rect>
<rect
x="8"
y="8"
width="13"
height="13"
rx="2"
fill="currentColor"
opacity="0.3"
></rect>
</svg>
</button>
</div>
</div>
<div class="toolbar-right">
<div class="collaborators" id="collaborators"></div>
<button
class="btn-icon"
onclick="showThemeModal()"
title="Themes"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 2a10 10 0 0 1 0 20"></path>
<line x1="2" y1="12" x2="22" y2="12"></line>
</svg>
</button>
<button
class="btn-icon"
onclick="startPresentation()"
title="Present (F5)"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="currentColor"
>
<polygon points="5 3 19 12 5 21 5 3"></polygon>
</svg>
</button>
<button
class="btn-primary"
onclick="savePresentation()"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"
></path>
<polyline
points="17 21 17 13 7 13 7 21"
></polyline>
<polyline points="7 3 7 8 15 8"></polyline>
</svg>
<span>Save</span>
</button>
</div>
</div>
<!-- Slide Canvas Area -->
<div class="slide-canvas-container" id="canvas-container">
<div class="slide-canvas" id="slide-canvas">
<!-- Elements rendered here -->
</div>
<!-- Selection handles (shown when element selected) -->
<div
class="selection-handles hidden"
id="selection-handles"
>
<div class="handle nw" data-handle="nw"></div>
<div class="handle n" data-handle="n"></div>
<div class="handle ne" data-handle="ne"></div>
<div class="handle w" data-handle="w"></div>
<div class="handle e" data-handle="e"></div>
<div class="handle sw" data-handle="sw"></div>
<div class="handle s" data-handle="s"></div>
<div class="handle se" data-handle="se"></div>
<div class="rotate-handle" data-handle="rotate"></div>
</div>
<!-- Cursor indicators for collaborators -->
<div class="cursor-indicators" id="cursor-indicators"></div>
</div>
<!-- Status Bar -->
<div class="slides-status-bar">
<div class="status-left">
<span
>Slide <span id="current-slide-num">1</span> of
<span id="total-slides">1</span></span
>
</div>
<div class="status-center">
<span id="save-status"></span>
</div>
<div class="status-right">
<span>Zoom:</span>
<div class="zoom-control">
<button class="btn-zoom" onclick="zoomOut()">
</button>
<span id="zoom-level">100</span>%
<button class="btn-zoom" onclick="zoomIn()">
+
</button>
</div>
</div>
</div>
</main>
<!-- Properties Panel -->
<aside class="slides-properties" id="properties-panel">
<div class="properties-header">
<h3>Properties</h3>
<button
class="btn-icon"
onclick="toggleProperties()"
title="Close"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="properties-content" id="properties-content">
<div class="property-group">
<label>Position</label>
<div class="property-row">
<div class="property-input">
<span>X</span>
<input
type="number"
id="prop-x"
onchange="updateElementPosition('x', this.value)"
/>
</div>
<div class="property-input">
<span>Y</span>
<input
type="number"
id="prop-y"
onchange="updateElementPosition('y', this.value)"
/>
</div>
</div>
</div>
<div class="property-group">
<label>Size</label>
<div class="property-row">
<div class="property-input">
<span>W</span>
<input
type="number"
id="prop-width"
onchange="updateElementSize('width', this.value)"
/>
</div>
<div class="property-input">
<span>H</span>
<input
type="number"
id="prop-height"
onchange="updateElementSize('height', this.value)"
/>
</div>
</div>
</div>
<div class="property-group">
<label>Rotation</label>
<div class="property-row">
<input
type="range"
id="prop-rotation"
min="0"
max="360"
value="0"
oninput="updateElementRotation(this.value)"
/>
<span id="rotation-value"></span>
</div>
</div>
<div class="property-group">
<label>Opacity</label>
<div class="property-row">
<input
type="range"
id="prop-opacity"
min="0"
max="100"
value="100"
oninput="updateElementOpacity(this.value)"
/>
<span id="opacity-value">100%</span>
</div>
</div>
</div>
</aside>
</div>
<!-- Context Menu -->
<div class="context-menu hidden" id="context-menu">
<div class="context-item" onclick="cutElement()">
Cut <span class="shortcut">Ctrl+X</span>
</div>
<div class="context-item" onclick="copyElement()">
Copy <span class="shortcut">Ctrl+C</span>
</div>
<div class="context-item" onclick="pasteElement()">
Paste <span class="shortcut">Ctrl+V</span>
</div>
<div class="context-divider"></div>
<div class="context-item" onclick="duplicateElement()">
Duplicate <span class="shortcut">Ctrl+D</span>
</div>
<div class="context-item" onclick="deleteElement()">
Delete <span class="shortcut">Del</span>
</div>
<div class="context-divider"></div>
<div class="context-item" onclick="bringToFront()">
Bring to Front
</div>
<div class="context-item" onclick="sendToBack()">Send to Back</div>
<div class="context-divider"></div>
<div class="context-item" onclick="lockElement()">Lock/Unlock</div>
</div>
<!-- Slide Context Menu -->
<div class="context-menu hidden" id="slide-context-menu">
<div class="context-item" onclick="addSlideAfter()">
Add Slide After
</div>
<div class="context-item" onclick="duplicateSlide()">
Duplicate Slide
</div>
<div class="context-divider"></div>
<div class="context-item" onclick="deleteSlide()">Delete Slide</div>
<div class="context-divider"></div>
<div class="context-item" onclick="showSlideBackground()">
Change Background
</div>
<div class="context-item" onclick="showSlideTransition()">
Transition...
</div>
</div>
<!-- Theme Modal -->
<div class="modal hidden" id="theme-modal">
<div class="modal-content">
<div class="modal-header">
<h3>Themes</h3>
<button
class="btn-close"
onclick="hideModal('theme-modal')"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="modal-body">
<div class="theme-grid">
<div class="theme-item" onclick="applyTheme('default')">
<div
class="theme-preview"
style="
background: linear-gradient(
135deg,
#3b82f6,
#1e40af
);
"
></div>
<span>Default</span>
</div>
<div class="theme-item" onclick="applyTheme('dark')">
<div
class="theme-preview"
style="
background: linear-gradient(
135deg,
#1e293b,
#0f172a
);
"
></div>
<span>Dark</span>
</div>
<div class="theme-item" onclick="applyTheme('minimal')">
<div
class="theme-preview"
style="
background: #ffffff;
border: 1px solid #e2e8f0;
"
></div>
<span>Minimal</span>
</div>
<div class="theme-item" onclick="applyTheme('nature')">
<div
class="theme-preview"
style="
background: linear-gradient(
135deg,
#22c55e,
#15803d
);
"
></div>
<span>Nature</span>
</div>
<div class="theme-item" onclick="applyTheme('sunset')">
<div
class="theme-preview"
style="
background: linear-gradient(
135deg,
#f97316,
#dc2626
);
"
></div>
<span>Sunset</span>
</div>
<div class="theme-item" onclick="applyTheme('ocean')">
<div
class="theme-preview"
style="
background: linear-gradient(
135deg,
#06b6d4,
#0284c7
);
"
></div>
<span>Ocean</span>
</div>
</div>
</div>
</div>
</div>
<!-- Shape Modal -->
<div class="modal hidden" id="shape-modal">
<div class="modal-content">
<div class="modal-header">
<h3>Insert Shape</h3>
<button
class="btn-close"
onclick="hideModal('shape-modal')"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="modal-body">
<div class="shape-grid">
<button
class="shape-btn"
onclick="addShape('rectangle')"
title="Rectangle"
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="#3b82f6"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="2"
></rect>
</svg>
</button>
<button
class="shape-btn"
onclick="addShape('rounded-rectangle')"
title="Rounded Rectangle"
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="#3b82f6"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="6"
></rect>
</svg>
</button>
<button
class="shape-btn"
onclick="addShape('ellipse')"
title="Ellipse"
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="#3b82f6"
>
<ellipse
cx="12"
cy="12"
rx="9"
ry="9"
></ellipse>
</svg>
</button>
<button
class="shape-btn"
onclick="addShape('triangle')"
title="Triangle"
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="#3b82f6"
>
<polygon points="12,3 21,21 3,21"></polygon>
</svg>
</button>
<button
class="shape-btn"
onclick="addShape('diamond')"
title="Diamond"
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="#3b82f6"
>
<polygon
points="12,2 22,12 12,22 2,12"
></polygon>
</svg>
</button>
<button
class="shape-btn"
onclick="addShape('star')"
title="Star"
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="#3b82f6"
>
<polygon
points="12,2 15,9 22,9 17,14 19,21 12,17 5,21 7,14 2,9 9,9"
></polygon>
</svg>
</button>
<button
class="shape-btn"
onclick="addShape('arrow-right')"
title="Arrow Right"
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="#3b82f6"
>
<polygon
points="2,8 14,8 14,4 22,12 14,20 14,16 2,16"
></polygon>
</svg>
</button>
<button
class="shape-btn"
onclick="addShape('callout')"
title="Callout"
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="#3b82f6"
>
<path
d="M3,3 L21,3 L21,15 L12,15 L6,21 L6,15 L3,15 Z"
></path>
</svg>
</button>
</div>
</div>
</div>
</div>
<!-- Chart Modal -->
<div class="modal hidden" id="chart-modal">
<div class="modal-content modal-large">
<div class="modal-header">
<h3>Insert Chart</h3>
<button
class="btn-close"
onclick="hideModal('chart-modal')"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="modal-body">
<div class="chart-type-selector">
<button class="chart-type-btn active" data-type="bar">
<svg
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect x="3" y="12" width="4" height="9"></rect>
<rect x="10" y="8" width="4" height="13"></rect>
<rect x="17" y="4" width="4" height="17"></rect>
</svg>
<span>Bar</span>
</button>
<button class="chart-type-btn" data-type="line">
<svg
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<polyline
points="3,17 8,12 13,16 21,6"
></polyline>
</svg>
<span>Line</span>
</button>
<button class="chart-type-btn" data-type="pie">
<svg
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="10"></circle>
<path
d="M12,12 L12,2 A10,10 0 0,1 21,16 Z"
></path>
</svg>
<span>Pie</span>
</button>
</div>
<div class="chart-data-input">
<label>Chart Data (CSV format)</label>
<textarea
id="chart-data-input"
rows="5"
placeholder="Label,Value
Q1,100
Q2,150
Q3,120
Q4,200"
></textarea>
</div>
<div class="modal-footer">
<button
class="btn-secondary"
onclick="hideModal('chart-modal')"
>
Cancel
</button>
<button class="btn-primary" onclick="insertChart()">
Insert Chart
</button>
</div>
</div>
</div>
</div>
<script src="/suite/slides/slides.js"></script>
</body>
</html>