| 1 | <html> |
| 2 | <head> |
| 3 | <script type="module"> |
| 4 | import { store } from "/components/modals/scheduler/scheduler-store.js"; |
| 5 | </script> |
| 6 | </head> |
| 7 | <body> |
| 8 | <div x-data> |
| 9 | <template x-if="$store.schedulerStore"> |
| 10 | <div> |
| 11 | <!-- Create Task Form --> |
| 12 | <div class="scheduler-form" x-show="$store.schedulerStore.isCreating"> |
| 13 | <div class="scheduler-form-header"> |
| 14 | <div class="scheduler-form-title">Create New Task</div> |
| 15 | </div> |
| 16 | <div class="buttons-container scheduler-editor-actions scheduler-editor-actions-top"> |
| 17 | <div class="buttons-left"></div> |
| 18 | <div class="buttons-right"> |
| 19 | <button type="button" class="button confirm" |
| 20 | @click="$store.schedulerStore.saveTask()">Save</button> |
| 21 | <button type="button" class="button cancel" |
| 22 | @click="$store.schedulerStore.cancelEdit()">Cancel</button> |
| 23 | </div> |
| 24 | </div> |
| 25 | |
| 26 | <div class="scheduler-form-grid"> |
| 27 | <div class="scheduler-form-field"> |
| 28 | <div class="label-help-wrapper"> |
| 29 | <label class="scheduler-form-label">Task Name</label> |
| 30 | <div class="scheduler-form-help">A unique name to identify this task</div> |
| 31 | </div> |
| 32 | <input type="text" x-model="$store.schedulerStore.editingTask.name" placeholder="Enter task name"> |
| 33 | </div> |
| 34 | |
| 35 | <div class="scheduler-form-field"> |
| 36 | <div class="label-help-wrapper"> |
| 37 | <label class="scheduler-form-label">Type</label> |
| 38 | <div class="scheduler-form-help">Task execution method</div> |
| 39 | </div> |
| 40 | <select x-model="$store.schedulerStore.editingTask.type"> |
| 41 | <option value="scheduled">Scheduled (Cron)</option> |
| 42 | <option value="adhoc">Ad-hoc (Manual)</option> |
| 43 | <option value="planned">Planned (Specific Times)</option> |
| 44 | </select> |
| 45 | </div> |
| 46 | |
| 47 | <div class="scheduler-form-field"> |
| 48 | <div class="label-help-wrapper"> |
| 49 | <label class="scheduler-form-label">Project</label> |
| 50 | <div class="scheduler-form-help" |
| 51 | x-text="$store.schedulerStore.editingTask.dedicated_context ? 'Inherited from the active chat project.' : 'Mirrors the shared context project.'"></div> |
| 52 | </div> |
| 53 | <div class="project-selector"> |
| 54 | <select class="scheduler-project-select" |
| 55 | x-model="$store.schedulerStore.selectedProjectSlug" |
| 56 | @change="$store.schedulerStore.onProjectSelect($event.target.value)"> |
| 57 | <option value="">No project</option> |
| 58 | <template x-for="proj in $store.schedulerStore.projectOptions" :key="proj.name"> |
| 59 | <option :value="proj.name" x-text="proj.title"></option> |
| 60 | </template> |
| 61 | </select> |
| 62 | </div> |
| 63 | </div> |
| 64 | |
| 65 | <div class="scheduler-form-field" x-show="$store.schedulerStore.isCreating"> |
| 66 | <div class="label-help-wrapper"> |
| 67 | <label class="scheduler-form-label">State</label> |
| 68 | <div class="scheduler-form-help">Select the initial state of the task</div> |
| 69 | </div> |
| 70 | <div> |
| 71 | <div class="scheduler-state-selector"> |
| 72 | <span class="scheduler-status-badge scheduler-status-idle" |
| 73 | :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'idle'}" |
| 74 | @click="$store.schedulerStore.editingTask.state = 'idle'">Idle</span> |
| 75 | <span class="scheduler-status-badge scheduler-status-running" |
| 76 | :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'running'}" |
| 77 | @click="$store.schedulerStore.editingTask.state = 'running'">Running</span> |
| 78 | <span class="scheduler-status-badge scheduler-status-disabled" |
| 79 | :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'disabled'}" |
| 80 | @click="$store.schedulerStore.editingTask.state = 'disabled'">Disabled</span> |
| 81 | <span class="scheduler-status-badge scheduler-status-error" |
| 82 | :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'error'}" |
| 83 | @click="$store.schedulerStore.editingTask.state = 'error'">Error</span> |
| 84 | </div> |
| 85 | <div class="scheduler-state-explanation"> |
| 86 | <span x-show="$store.schedulerStore.editingTask.state === 'idle'"><strong>Idle</strong>: Ready to run</span> |
| 87 | <span x-show="$store.schedulerStore.editingTask.state === 'running'"><strong>Running</strong>: Currently executing</span> |
| 88 | <span x-show="$store.schedulerStore.editingTask.state === 'disabled'"><strong>Disabled</strong>: Won't execute automatically</span> |
| 89 | <span x-show="$store.schedulerStore.editingTask.state === 'error'"><strong>Error</strong>: Task encountered an error</span> |
| 90 | </div> |
| 91 | </div> |
| 92 | </div> |
| 93 | |
| 94 | <div class="scheduler-form-field full-width" |
| 95 | x-show="$store.schedulerStore.editingTask.type === 'scheduled'"> |
| 96 | <div class="label-help-wrapper"> |
| 97 | <label class="scheduler-form-label">Schedule</label> |
| 98 | <div class="scheduler-form-help">Cron schedule for automated execution (minute hour day month weekday)</div> |
| 99 | </div> |
| 100 | <div class="scheduler-schedule-builder"> |
| 101 | <div class="scheduler-schedule-field"> |
| 102 | <span class="scheduler-schedule-label">Minute</span> |
| 103 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.minute" |
| 104 | placeholder="*" maxlength="9"> |
| 105 | </div> |
| 106 | <div class="scheduler-schedule-field"> |
| 107 | <span class="scheduler-schedule-label">Hour</span> |
| 108 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.hour" |
| 109 | placeholder="*" maxlength="9"> |
| 110 | </div> |
| 111 | <div class="scheduler-schedule-field"> |
| 112 | <span class="scheduler-schedule-label">Day</span> |
| 113 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.day" |
| 114 | placeholder="*" maxlength="9"> |
| 115 | </div> |
| 116 | <div class="scheduler-schedule-field"> |
| 117 | <span class="scheduler-schedule-label">Month</span> |
| 118 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.month" |
| 119 | placeholder="*" maxlength="9"> |
| 120 | </div> |
| 121 | <div class="scheduler-schedule-field"> |
| 122 | <span class="scheduler-schedule-label">Weekday</span> |
| 123 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.weekday" |
| 124 | placeholder="*" maxlength="9"> |
| 125 | </div> |
| 126 | </div> |
| 127 | </div> |
| 128 | |
| 129 | <div class="scheduler-form-field full-width" |
| 130 | x-show="$store.schedulerStore.editingTask.type === 'planned'" |
| 131 | x-effect="if ($store.schedulerStore.isCreating && $store.schedulerStore.editingTask.type === 'planned') { $store.schedulerStore.initFlatpickr('create') }"> |
| 132 | <div class="label-help-wrapper"> |
| 133 | <label class="scheduler-form-label">Plan</label> |
| 134 | <div class="scheduler-form-help">Specific execution times for this task</div> |
| 135 | </div> |
| 136 | <div class="scheduler-plan-builder"> |
| 137 | <div class="scheduler-plan-todo"> |
| 138 | <span class="scheduler-plan-label">Upcoming Executions</span> |
| 139 | <div class="scheduler-todo-list"> |
| 140 | <template x-if="$store.schedulerStore.editingTask.plan && Array.isArray($store.schedulerStore.editingTask.plan.todo) && $store.schedulerStore.editingTask.plan.todo.length > 0"> |
| 141 | <template x-for="(time, index) in $store.schedulerStore.editingTask.plan.todo" :key="index"> |
| 142 | <div class="scheduler-todo-item"> |
| 143 | <span x-text="$store.schedulerStore.formatDate(time)"></span> |
| 144 | <button @click.prevent="$store.schedulerStore.editingTask.plan.todo.splice(index, 1)" |
| 145 | class="scheduler-todo-remove"> |
| 146 | <x-icon name="close"></x-icon> |
| 147 | </button> |
| 148 | </div> |
| 149 | </template> |
| 150 | </template> |
| 151 | <template x-if="!$store.schedulerStore.editingTask.plan || !$store.schedulerStore.editingTask.plan.todo || $store.schedulerStore.editingTask.plan.todo.length === 0"> |
| 152 | <div class="scheduler-empty-plan"> |
| 153 | No scheduled execution times yet. Add one below. |
| 154 | </div> |
| 155 | </template> |
| 156 | <div class="scheduler-add-todo"> |
| 157 | <input type="text" id="newPlannedTime-create" |
| 158 | class="scheduler-flatpickr-input" |
| 159 | placeholder="Select date and time"> |
| 160 | <button @click.prevent="$store.schedulerStore.addPlannedTime('create')" |
| 161 | class="btn btn-ok scheduler-add-todo-button"> |
| 162 | <x-icon name="add"></x-icon> |
| 163 | Add Time |
| 164 | </button> |
| 165 | </div> |
| 166 | </div> |
| 167 | </div> |
| 168 | </div> |
| 169 | </div> |
| 170 | |
| 171 | <div class="scheduler-form-field full-width" |
| 172 | x-show="$store.schedulerStore.editingTask.type === 'adhoc'"> |
| 173 | <div class="label-help-wrapper"> |
| 174 | <label class="scheduler-form-label">Token</label> |
| 175 | <div class="scheduler-form-help">Token used to trigger this task externally</div> |
| 176 | </div> |
| 177 | <div class="input-group"> |
| 178 | <input type="text" x-model="$store.schedulerStore.editingTask.token" |
| 179 | placeholder="Token for ad-hoc task"> |
| 180 | <button class="btn btn-action generate-token" |
| 181 | @click="$store.schedulerStore.editingTask.token = $store.schedulerStore.generateRandomToken()" |
| 182 | title="Generate Token"> |
| 183 | <x-icon name="refresh"></x-icon> |
| 184 | Generate |
| 185 | </button> |
| 186 | </div> |
| 187 | </div> |
| 188 | |
| 189 | <div class="scheduler-form-field full-width"> |
| 190 | <div class="label-help-wrapper"> |
| 191 | <label class="scheduler-form-label">System Prompt</label> |
| 192 | <div class="scheduler-form-help">System-level instructions for the assistant</div> |
| 193 | </div> |
| 194 | <textarea x-model="$store.schedulerStore.editingTask.system_prompt" |
| 195 | placeholder="System instructions for the AI"></textarea> |
| 196 | </div> |
| 197 | |
| 198 | <div class="scheduler-form-field full-width"> |
| 199 | <div class="label-help-wrapper"> |
| 200 | <label class="scheduler-form-label">User Prompt</label> |
| 201 | <div class="scheduler-form-help">The main task prompt that will be executed</div> |
| 202 | </div> |
| 203 | <textarea x-model="$store.schedulerStore.editingTask.prompt" |
| 204 | placeholder="User message for the AI"></textarea> |
| 205 | </div> |
| 206 | |
| 207 | <div class="scheduler-form-field full-width"> |
| 208 | <div class="label-help-wrapper"> |
| 209 | <label class="scheduler-form-label">Attachments</label> |
| 210 | <div class="scheduler-form-help">Container file paths or URLs, one per line</div> |
| 211 | </div> |
| 212 | <textarea x-model="$store.schedulerStore.attachmentsText" |
| 213 | placeholder="Enter file paths or URLs, one per line"></textarea> |
| 214 | </div> |
| 215 | </div> |
| 216 | </div> |
| 217 | |
| 218 | <!-- Edit Task Form --> |
| 219 | <div class="scheduler-form" x-show="$store.schedulerStore.isEditing"> |
| 220 | <div class="scheduler-form-header"> |
| 221 | <div class="scheduler-form-title">Edit Task</div> |
| 222 | </div> |
| 223 | <div class="buttons-container scheduler-editor-actions scheduler-editor-actions-top"> |
| 224 | <div class="buttons-left"> |
| 225 | <button type="button" class="button cancel" |
| 226 | @click="$confirmClick($event, () => $store.schedulerStore.deleteTask($store.schedulerStore.editingTask.uuid))">Delete</button> |
| 227 | </div> |
| 228 | <div class="buttons-right"> |
| 229 | <button type="button" class="button confirm" |
| 230 | @click="$store.schedulerStore.saveTask()">Save</button> |
| 231 | <button type="button" class="button cancel" |
| 232 | @click="$store.schedulerStore.cancelEdit()">Cancel</button> |
| 233 | </div> |
| 234 | </div> |
| 235 | |
| 236 | <div class="scheduler-form-grid"> |
| 237 | <div class="scheduler-form-field"> |
| 238 | <div class="label-help-wrapper"> |
| 239 | <label class="scheduler-form-label">Task Name</label> |
| 240 | <div class="scheduler-form-help">A unique name to identify this task</div> |
| 241 | </div> |
| 242 | <input type="text" x-model="$store.schedulerStore.editingTask.name" placeholder="Enter task name"> |
| 243 | </div> |
| 244 | |
| 245 | <div class="scheduler-form-field"> |
| 246 | <div class="label-help-wrapper"> |
| 247 | <label class="scheduler-form-label">Task Type</label> |
| 248 | <div class="scheduler-form-help">Task type cannot be changed after creation</div> |
| 249 | </div> |
| 250 | <select x-model="$store.schedulerStore.editingTask.type" disabled> |
| 251 | <option value="scheduled">Scheduled Task</option> |
| 252 | <option value="adhoc">Ad-hoc Task</option> |
| 253 | <option value="planned">Planned Task</option> |
| 254 | </select> |
| 255 | </div> |
| 256 | |
| 257 | <div class="scheduler-form-field"> |
| 258 | <div class="label-help-wrapper"> |
| 259 | <label class="scheduler-form-label">Project</label> |
| 260 | <div class="scheduler-form-help" |
| 261 | x-text="$store.schedulerStore.editingTask.dedicated_context ? 'Dedicated tasks inherit the active chat project.' : 'Shared tasks mirror the project assigned to their context.'"></div> |
| 262 | </div> |
| 263 | <div class="project-display"> |
| 264 | <span class="project-color-ball" |
| 265 | :style="$store.schedulerStore.editingTask.project?.color ? { backgroundColor: $store.schedulerStore.editingTask.project.color } : { border: '1px solid var(--color-border)' }"></span> |
| 266 | <span x-text="$store.schedulerStore.formatProjectLabel($store.schedulerStore.editingTask.project)"></span> |
| 267 | </div> |
| 268 | </div> |
| 269 | |
| 270 | <div class="scheduler-form-field" x-show="$store.schedulerStore.isEditing"> |
| 271 | <div class="label-help-wrapper"> |
| 272 | <label class="scheduler-form-label">State</label> |
| 273 | <div class="scheduler-form-help">Change the task's state</div> |
| 274 | </div> |
| 275 | <div> |
| 276 | <div class="scheduler-state-selector"> |
| 277 | <span class="scheduler-status-badge scheduler-status-idle" |
| 278 | :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'idle'}" |
| 279 | @click="$store.schedulerStore.editingTask.state = 'idle'">Idle</span> |
| 280 | <span class="scheduler-status-badge scheduler-status-running" |
| 281 | :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'running'}" |
| 282 | @click="$store.schedulerStore.editingTask.state = 'running'">Running</span> |
| 283 | <span class="scheduler-status-badge scheduler-status-disabled" |
| 284 | :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'disabled'}" |
| 285 | @click="$store.schedulerStore.editingTask.state = 'disabled'">Disabled</span> |
| 286 | <span class="scheduler-status-badge scheduler-status-error" |
| 287 | :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'error'}" |
| 288 | @click="$store.schedulerStore.editingTask.state = 'error'">Error</span> |
| 289 | </div> |
| 290 | <div class="scheduler-state-explanation"> |
| 291 | <span x-show="$store.schedulerStore.editingTask.state === 'idle'"><strong>Idle</strong>: Ready to run</span> |
| 292 | <span x-show="$store.schedulerStore.editingTask.state === 'running'"><strong>Running</strong>: Currently executing</span> |
| 293 | <span x-show="$store.schedulerStore.editingTask.state === 'disabled'"><strong>Disabled</strong>: Won't execute automatically</span> |
| 294 | <span x-show="$store.schedulerStore.editingTask.state === 'error'"><strong>Error</strong>: Task encountered an error</span> |
| 295 | </div> |
| 296 | </div> |
| 297 | </div> |
| 298 | |
| 299 | <div class="scheduler-form-field full-width" |
| 300 | x-show="$store.schedulerStore.editingTask && $store.schedulerStore.editingTask.type === 'scheduled'"> |
| 301 | <div class="label-help-wrapper"> |
| 302 | <label class="scheduler-form-label">Schedule (Cron Expression)</label> |
| 303 | <div class="scheduler-form-help">Format: minute hour day month weekday (e.g., "* * * * *" for every minute)</div> |
| 304 | </div> |
| 305 | <div class="scheduler-schedule-builder"> |
| 306 | <div class="scheduler-schedule-field"> |
| 307 | <span class="scheduler-schedule-label">Minute</span> |
| 308 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.minute" |
| 309 | placeholder="*" maxlength="9"> |
| 310 | </div> |
| 311 | <div class="scheduler-schedule-field"> |
| 312 | <span class="scheduler-schedule-label">Hour</span> |
| 313 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.hour" |
| 314 | placeholder="*" maxlength="9"> |
| 315 | </div> |
| 316 | <div class="scheduler-schedule-field"> |
| 317 | <span class="scheduler-schedule-label">Day</span> |
| 318 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.day" |
| 319 | placeholder="*" maxlength="9"> |
| 320 | </div> |
| 321 | <div class="scheduler-schedule-field"> |
| 322 | <span class="scheduler-schedule-label">Month</span> |
| 323 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.month" |
| 324 | placeholder="*" maxlength="9"> |
| 325 | </div> |
| 326 | <div class="scheduler-schedule-field"> |
| 327 | <span class="scheduler-schedule-label">Weekday</span> |
| 328 | <input type="text" x-model="$store.schedulerStore.editingTask.schedule.weekday" |
| 329 | placeholder="*" maxlength="9"> |
| 330 | </div> |
| 331 | </div> |
| 332 | </div> |
| 333 | |
| 334 | <div class="scheduler-form-field full-width" |
| 335 | x-show="$store.schedulerStore.editingTask.type === 'planned'" |
| 336 | x-effect="if ($store.schedulerStore.isEditing && $store.schedulerStore.editingTask.type === 'planned') { $store.schedulerStore.initFlatpickr('edit') }"> |
| 337 | <div class="label-help-wrapper"> |
| 338 | <label class="scheduler-form-label">Plan</label> |
| 339 | <div class="scheduler-form-help">Specific execution times for this task</div> |
| 340 | </div> |
| 341 | <div class="scheduler-plan-builder"> |
| 342 | <div class="scheduler-plan-todo"> |
| 343 | <span class="scheduler-plan-label">Upcoming Executions</span> |
| 344 | <div class="scheduler-todo-list"> |
| 345 | <template x-if="$store.schedulerStore.editingTask.plan && Array.isArray($store.schedulerStore.editingTask.plan.todo) && $store.schedulerStore.editingTask.plan.todo.length > 0"> |
| 346 | <template x-for="(time, index) in $store.schedulerStore.editingTask.plan.todo" :key="index"> |
| 347 | <div class="scheduler-todo-item"> |
| 348 | <span x-text="$store.schedulerStore.formatDate(time)"></span> |
| 349 | <button @click.prevent="$store.schedulerStore.editingTask.plan.todo.splice(index, 1)" |
| 350 | class="scheduler-todo-remove"> |
| 351 | <x-icon name="close"></x-icon> |
| 352 | </button> |
| 353 | </div> |
| 354 | </template> |
| 355 | </template> |
| 356 | <template x-if="!$store.schedulerStore.editingTask.plan || !$store.schedulerStore.editingTask.plan.todo || $store.schedulerStore.editingTask.plan.todo.length === 0"> |
| 357 | <div class="scheduler-empty-plan"> |
| 358 | No scheduled execution times yet. Add one below. |
| 359 | </div> |
| 360 | </template> |
| 361 | <div class="scheduler-add-todo"> |
| 362 | <input type="text" id="newPlannedTime-edit" |
| 363 | class="scheduler-flatpickr-input" |
| 364 | placeholder="Select date and time"> |
| 365 | <button @click.prevent="$store.schedulerStore.addPlannedTime('edit')" |
| 366 | class="btn btn-ok scheduler-add-todo-button"> |
| 367 | <x-icon name="add"></x-icon> |
| 368 | Add Time |
| 369 | </button> |
| 370 | </div> |
| 371 | </div> |
| 372 | </div> |
| 373 | </div> |
| 374 | </div> |
| 375 | |
| 376 | <div class="scheduler-form-field full-width" |
| 377 | x-show="$store.schedulerStore.editingTask.type === 'adhoc'"> |
| 378 | <div class="label-help-wrapper"> |
| 379 | <label class="scheduler-form-label">Token</label> |
| 380 | <div class="scheduler-form-help">Token used to trigger this task externally</div> |
| 381 | </div> |
| 382 | <div class="input-group"> |
| 383 | <input type="text" x-model="$store.schedulerStore.editingTask.token" |
| 384 | placeholder="Token for ad-hoc task"> |
| 385 | <button class="btn btn-action generate-token" |
| 386 | @click="$store.schedulerStore.editingTask.token = $store.schedulerStore.generateRandomToken()" |
| 387 | title="Generate Token"> |
| 388 | <x-icon name="refresh"></x-icon> |
| 389 | Generate |
| 390 | </button> |
| 391 | </div> |
| 392 | </div> |
| 393 | |
| 394 | <div class="scheduler-form-field full-width"> |
| 395 | <div class="label-help-wrapper"> |
| 396 | <label class="scheduler-form-label">System Prompt</label> |
| 397 | <div class="scheduler-form-help">System-level instructions for the assistant</div> |
| 398 | </div> |
| 399 | <textarea x-model="$store.schedulerStore.editingTask.system_prompt" |
| 400 | placeholder="System instructions for the AI"></textarea> |
| 401 | </div> |
| 402 | |
| 403 | <div class="scheduler-form-field full-width"> |
| 404 | <div class="label-help-wrapper"> |
| 405 | <label class="scheduler-form-label">User Prompt</label> |
| 406 | <div class="scheduler-form-help">The main task prompt that will be executed</div> |
| 407 | </div> |
| 408 | <textarea x-model="$store.schedulerStore.editingTask.prompt" |
| 409 | placeholder="User message for the AI"></textarea> |
| 410 | </div> |
| 411 | |
| 412 | <div class="scheduler-form-field full-width"> |
| 413 | <div class="label-help-wrapper"> |
| 414 | <label class="scheduler-form-label">Attachments</label> |
| 415 | <div class="scheduler-form-help">Container file paths or URLs, one per line</div> |
| 416 | </div> |
| 417 | <textarea x-model="$store.schedulerStore.attachmentsText" |
| 418 | placeholder="Enter file paths or URLs, one per line"></textarea> |
| 419 | </div> |
| 420 | </div> |
| 421 | </div> |
| 422 | </div> |
| 423 | </template> |
| 424 | </div> |
| 425 | |
| 426 | <style> |
| 427 | /* Form header with Save/Cancel buttons - aligns with Projects pattern */ |
| 428 | |
| 429 | .scheduler-form-title { |
| 430 | font-size: 1.2rem; |
| 431 | font-weight: 600; |
| 432 | color: var(--color-primary); |
| 433 | } |
| 434 | |
| 435 | .scheduler-form-actions { |
| 436 | display: flex; |
| 437 | gap: 0.5rem; |
| 438 | } |
| 439 | |
| 440 | .scheduler-editor-actions { |
| 441 | margin: 0 0 1rem 0; |
| 442 | } |
| 443 | |
| 444 | /* Generate token button - extends .btn-action from buttons.css */ |
| 445 | .btn-action.generate-token { |
| 446 | padding: 0.4rem 0.75rem; |
| 447 | white-space: nowrap; |
| 448 | } |
| 449 | |
| 450 | /* Todo remove button with Material Symbol */ |
| 451 | .scheduler-todo-remove { |
| 452 | background: none; |
| 453 | border: 1px solid var(--color-border); |
| 454 | padding: 0.15rem; |
| 455 | color: var(--color-text); |
| 456 | opacity: 0.7; |
| 457 | display: inline-flex; |
| 458 | align-items: center; |
| 459 | justify-content: center; |
| 460 | border-radius: 4px; |
| 461 | cursor: pointer; |
| 462 | } |
| 463 | |
| 464 | .scheduler-todo-remove .material-symbols-outlined { |
| 465 | font-size: 16px; |
| 466 | } |
| 467 | |
| 468 | .scheduler-todo-remove:hover { |
| 469 | opacity: 1; |
| 470 | border-color: var(--color-accent); |
| 471 | color: var(--color-accent); |
| 472 | } |
| 473 | |
| 474 | /* Add todo button styling */ |
| 475 | .scheduler-add-todo-button { |
| 476 | display: inline-flex; |
| 477 | align-items: center; |
| 478 | gap: 0.25rem; |
| 479 | } |
| 480 | |
| 481 | .scheduler-add-todo-button .material-symbols-outlined { |
| 482 | font-size: 18px; |
| 483 | } |
| 484 | |
| 485 | /* Project color ball */ |
| 486 | .project-color-ball { |
| 487 | display: inline-block; |
| 488 | width: 10px; |
| 489 | height: 10px; |
| 490 | border-radius: 50%; |
| 491 | margin-right: 6px; |
| 492 | vertical-align: middle; |
| 493 | } |
| 494 | |
| 495 | .project-display { |
| 496 | display: flex; |
| 497 | align-items: center; |
| 498 | padding: 0.5rem; |
| 499 | background: var(--color-background); |
| 500 | border: 1px solid var(--color-border); |
| 501 | border-radius: 4px; |
| 502 | } |
| 503 | </style> |
| 504 | </body> |
| 505 | </html> |
| 506 |