dynamic colours in website settings
This commit is contained in:
Binary file not shown.
42
migrations/versions/9faab7ef6036_add_site_settings_table.py
Normal file
42
migrations/versions/9faab7ef6036_add_site_settings_table.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""Add site_settings table
|
||||||
|
|
||||||
|
Revision ID: 9faab7ef6036
|
||||||
|
Revises: ca9026520dad
|
||||||
|
Create Date: 2025-05-25 21:16:39.683736
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '9faab7ef6036'
|
||||||
|
down_revision = 'ca9026520dad'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('site_settings',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('primary_color', sa.String(length=7), nullable=True),
|
||||||
|
sa.Column('secondary_color', sa.String(length=7), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
op.drop_table('color_settings')
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('color_settings',
|
||||||
|
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('primary_color', sa.VARCHAR(length=7), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('secondary_color', sa.VARCHAR(length=7), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('updated_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('color_settings_pkey'))
|
||||||
|
)
|
||||||
|
op.drop_table('site_settings')
|
||||||
|
# ### end Alembic commands ###
|
||||||
Binary file not shown.
17
models.py
17
models.py
@@ -124,4 +124,19 @@ class TrashedFile(db.Model):
|
|||||||
deleter = db.relationship('User', foreign_keys=[deleted_by], backref='deleted_trashed_files') # Changed from deleted_files to deleted_trashed_files
|
deleter = db.relationship('User', foreign_keys=[deleted_by], backref='deleted_trashed_files') # Changed from deleted_files to deleted_trashed_files
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'<TrashedFile {self.name} ({self.type}) from {self.original_path}>'
|
return f'<TrashedFile {self.name} ({self.type}) from {self.original_path}>'
|
||||||
|
|
||||||
|
class SiteSettings(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
primary_color = db.Column(db.String(7), default='#16767b') # Default from colors.css
|
||||||
|
secondary_color = db.Column(db.String(7), default='#741b5f') # Default from colors.css
|
||||||
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_settings(cls):
|
||||||
|
settings = cls.query.first()
|
||||||
|
if not settings:
|
||||||
|
settings = cls()
|
||||||
|
db.session.add(settings)
|
||||||
|
db.session.commit()
|
||||||
|
return settings
|
||||||
Binary file not shown.
130
routes/main.py
130
routes/main.py
@@ -1,6 +1,6 @@
|
|||||||
from flask import render_template, Blueprint, redirect, url_for, request, flash
|
from flask import render_template, Blueprint, redirect, url_for, request, flash, Response
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
from models import User, db, Room, RoomFile, RoomMemberPermission
|
from models import User, db, Room, RoomFile, RoomMemberPermission, SiteSettings
|
||||||
import os
|
import os
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
from sqlalchemy import func, case, literal_column, text
|
from sqlalchemy import func, case, literal_column, text
|
||||||
@@ -326,4 +326,128 @@ def init_routes(main_bp):
|
|||||||
@main_bp.route('/settings')
|
@main_bp.route('/settings')
|
||||||
@login_required
|
@login_required
|
||||||
def settings():
|
def settings():
|
||||||
return render_template('settings/settings.html')
|
if not current_user.is_admin:
|
||||||
|
flash('Only administrators can access settings.', 'error')
|
||||||
|
return redirect(url_for('main.dashboard'))
|
||||||
|
|
||||||
|
site_settings = SiteSettings.get_settings()
|
||||||
|
return render_template('settings/settings.html',
|
||||||
|
primary_color=site_settings.primary_color,
|
||||||
|
secondary_color=site_settings.secondary_color)
|
||||||
|
|
||||||
|
@main_bp.route('/settings/colors', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def update_colors():
|
||||||
|
if not current_user.is_admin:
|
||||||
|
flash('Only administrators can update settings.', 'error')
|
||||||
|
return redirect(url_for('main.dashboard'))
|
||||||
|
|
||||||
|
primary_color = request.form.get('primary_color')
|
||||||
|
secondary_color = request.form.get('secondary_color')
|
||||||
|
|
||||||
|
if not primary_color or not secondary_color:
|
||||||
|
flash('Both primary and secondary colors are required.', 'error')
|
||||||
|
return redirect(url_for('main.settings'))
|
||||||
|
|
||||||
|
site_settings = SiteSettings.get_settings()
|
||||||
|
site_settings.primary_color = primary_color
|
||||||
|
site_settings.secondary_color = secondary_color
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.session.commit()
|
||||||
|
flash('Color settings updated successfully!', 'success')
|
||||||
|
except Exception as e:
|
||||||
|
db.session.rollback()
|
||||||
|
flash('An error occurred while updating color settings.', 'error')
|
||||||
|
|
||||||
|
return redirect(url_for('main.settings'))
|
||||||
|
|
||||||
|
@main_bp.route('/settings/colors/reset', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def reset_colors():
|
||||||
|
if not current_user.is_admin:
|
||||||
|
flash('Only administrators can update settings.', 'error')
|
||||||
|
return redirect(url_for('main.dashboard'))
|
||||||
|
|
||||||
|
site_settings = SiteSettings.get_settings()
|
||||||
|
site_settings.primary_color = '#16767b' # Default from colors.css
|
||||||
|
site_settings.secondary_color = '#741b5f' # Default from colors.css
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.session.commit()
|
||||||
|
flash('Colors reset to defaults successfully!', 'success')
|
||||||
|
except Exception as e:
|
||||||
|
db.session.rollback()
|
||||||
|
flash('An error occurred while resetting colors.', 'error')
|
||||||
|
|
||||||
|
return redirect(url_for('main.settings'))
|
||||||
|
|
||||||
|
@main_bp.route('/dynamic-colors.css')
|
||||||
|
def dynamic_colors():
|
||||||
|
site_settings = SiteSettings.get_settings()
|
||||||
|
|
||||||
|
# Calculate derived colors
|
||||||
|
def hex_to_rgb(hex_color):
|
||||||
|
hex_color = hex_color.lstrip('#')
|
||||||
|
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
|
||||||
|
|
||||||
|
def rgb_to_hex(rgb):
|
||||||
|
return '#{:02x}{:02x}{:02x}'.format(rgb[0], rgb[1], rgb[2])
|
||||||
|
|
||||||
|
def lighten_color(hex_color, amount):
|
||||||
|
rgb = hex_to_rgb(hex_color)
|
||||||
|
return rgb_to_hex(tuple(min(255, int(c + (255 - c) * amount)) for c in rgb))
|
||||||
|
|
||||||
|
# Calculate all color variants
|
||||||
|
primary_light = lighten_color(site_settings.primary_color, 0.15)
|
||||||
|
primary_bg_light = lighten_color(site_settings.primary_color, 0.9)
|
||||||
|
primary_opacity_15 = site_settings.primary_color + '26'
|
||||||
|
|
||||||
|
secondary_light = lighten_color(site_settings.secondary_color, 0.15)
|
||||||
|
secondary_bg_light = lighten_color(site_settings.secondary_color, 0.9)
|
||||||
|
secondary_opacity_15 = site_settings.secondary_color + '26'
|
||||||
|
|
||||||
|
# Calculate chart colors
|
||||||
|
primary_chart_light = lighten_color(site_settings.primary_color, 0.2)
|
||||||
|
primary_chart_lighter = lighten_color(site_settings.primary_color, 0.4)
|
||||||
|
primary_chart_lightest = lighten_color(site_settings.primary_color, 0.6)
|
||||||
|
primary_chart_pale = lighten_color(site_settings.primary_color, 0.8)
|
||||||
|
|
||||||
|
secondary_chart_light = lighten_color(site_settings.secondary_color, 0.2)
|
||||||
|
secondary_chart_lighter = lighten_color(site_settings.secondary_color, 0.4)
|
||||||
|
secondary_chart_lightest = lighten_color(site_settings.secondary_color, 0.6)
|
||||||
|
secondary_chart_pale = lighten_color(site_settings.secondary_color, 0.8)
|
||||||
|
|
||||||
|
css = f"""
|
||||||
|
:root {{
|
||||||
|
/* Primary Colors */
|
||||||
|
--primary-color: {site_settings.primary_color};
|
||||||
|
--primary-light: {primary_light};
|
||||||
|
--primary-bg-light: {primary_bg_light};
|
||||||
|
--primary-opacity-15: {primary_opacity_15};
|
||||||
|
|
||||||
|
/* Secondary Colors */
|
||||||
|
--secondary-color: {site_settings.secondary_color};
|
||||||
|
--secondary-light: {secondary_light};
|
||||||
|
--secondary-bg-light: {secondary_bg_light};
|
||||||
|
--secondary-opacity-15: {secondary_opacity_15};
|
||||||
|
|
||||||
|
/* Chart Colors */
|
||||||
|
--chart-primary: {site_settings.primary_color};
|
||||||
|
--chart-secondary: {site_settings.secondary_color};
|
||||||
|
--chart-warning: #ffd700;
|
||||||
|
|
||||||
|
/* Primary Chart Colors */
|
||||||
|
--chart-primary-light: {primary_chart_light};
|
||||||
|
--chart-primary-lighter: {primary_chart_lighter};
|
||||||
|
--chart-primary-lightest: {primary_chart_lightest};
|
||||||
|
--chart-primary-pale: {primary_chart_pale};
|
||||||
|
|
||||||
|
/* Secondary Chart Colors */
|
||||||
|
--chart-secondary-light: {secondary_chart_light};
|
||||||
|
--chart-secondary-lighter: {secondary_chart_lighter};
|
||||||
|
--chart-secondary-lightest: {secondary_chart_lightest};
|
||||||
|
--chart-secondary-pale: {secondary_chart_pale};
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
return Response(css, mimetype='text/css')
|
||||||
@@ -39,9 +39,9 @@
|
|||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 0 18px;
|
padding: 0 18px;
|
||||||
background-color: rgba(22,118,123,0.08);
|
background-color: var(--primary-opacity-8);
|
||||||
color: #16767b;
|
color: var(--primary-color);
|
||||||
border: 1px solid #16767b22;
|
border: 1px solid var(--primary-opacity-15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-save-member {
|
.btn-save-member {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.btn-group .btn.active {
|
.btn-group .btn.active {
|
||||||
background-color: #e6f3f4 !important;
|
background-color: var(--primary-bg-light) !important;
|
||||||
border-color: #16767b !important;
|
border-color: var(--primary-color) !important;
|
||||||
color: #16767b !important;
|
color: var(--primary-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-group .btn:not(.active) {
|
.btn-group .btn:not(.active) {
|
||||||
background-color: #fff !important;
|
background-color: var(--white) !important;
|
||||||
border-color: #e9ecef !important;
|
border-color: var(--border-light) !important;
|
||||||
color: #6c757d !important;
|
color: var(--text-muted) !important;
|
||||||
}
|
}
|
||||||
@@ -126,8 +126,8 @@ function renderFiles(files) {
|
|||||||
</tr></thead><tbody>`;
|
</tr></thead><tbody>`;
|
||||||
files.forEach((file, idx) => {
|
files.forEach((file, idx) => {
|
||||||
let icon = file.type === 'folder'
|
let icon = file.type === 'folder'
|
||||||
? `<i class='fas fa-folder' style='font-size:1.5rem;color:#16767b;'></i>`
|
? `<i class='fas fa-folder' style='font-size:1.5rem;color:var(--primary-color);'></i>`
|
||||||
: `<i class='fas fa-file-alt' style='font-size:1.5rem;color:#741b5f;'></i>`;
|
: `<i class='fas fa-file-alt' style='font-size:1.5rem;color:var(--secondary-color);'></i>`;
|
||||||
let size = file.size !== '-' ? (file.size > 0 ? (file.size < 1024*1024 ? (file.size/1024).toFixed(1)+' KB' : (file.size/1024/1024).toFixed(2)+' MB') : '0 KB') : '-';
|
let size = file.size !== '-' ? (file.size > 0 ? (file.size < 1024*1024 ? (file.size/1024).toFixed(1)+' KB' : (file.size/1024/1024).toFixed(2)+' MB') : '0 KB') : '-';
|
||||||
let actionsArr = [];
|
let actionsArr = [];
|
||||||
let dblClickAction = '';
|
let dblClickAction = '';
|
||||||
@@ -138,16 +138,16 @@ function renderFiles(files) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isTrashPage) {
|
if (isTrashPage) {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Restore' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='event.stopPropagation();restoreFile("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-undo'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Restore' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='event.stopPropagation();restoreFile("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-undo'></i></button>`);
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete Permanently' style='background-color:rgba(220,53,69,0.08);color:#dc3545;' onclick='event.stopPropagation();showPermanentDeleteModal("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-trash'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete Permanently' style='background-color:var(--danger-opacity-15);color:var(--danger-color);' onclick='event.stopPropagation();showPermanentDeleteModal("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-trash'></i></button>`);
|
||||||
} else {
|
} else {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'rgba(255,215,0,0.15)' : 'rgba(22,118,123,0.08)'};color:${file.starred ? '#ffd700' : '#16767b'};' onclick='event.stopPropagation();toggleStar("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-star'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'var(--warning-opacity-15)' : 'var(--primary-opacity-8)'};color:${file.starred ? 'var(--warning-color)' : 'var(--primary-color)'};' onclick='event.stopPropagation();toggleStar("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-star'></i></button>`);
|
||||||
}
|
}
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='event.stopPropagation();showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='event.stopPropagation();showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
||||||
const actions = actionsArr.join('');
|
const actions = actionsArr.join('');
|
||||||
table += `<tr ${dblClickAction} onclick='navigateToFile(${file.room_id}, "${file.name}", "${file.path}", "${file.type}")'>
|
table += `<tr ${dblClickAction} onclick='navigateToFile(${file.room_id}, "${file.name}", "${file.path}", "${file.type}")'>
|
||||||
<td class='file-icon'><span style="display:inline-flex;align-items:center;gap:1.2rem;">${icon}</span></td>
|
<td class='file-icon'><span style="display:inline-flex;align-items:center;gap:1.2rem;">${icon}</span></td>
|
||||||
<td class='room-name'><button class='btn btn-sm' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='event.stopPropagation();window.location.href="/rooms/${file.room_id}"'><i class='fas fa-door-open me-1'></i>${file.room_name || 'Room ' + file.room_id}</button></td>
|
<td class='room-name'><button class='btn btn-sm' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='event.stopPropagation();window.location.href="/rooms/${file.room_id}"'><i class='fas fa-door-open me-1'></i>${file.room_name || 'Room ' + file.room_id}</button></td>
|
||||||
<td class='file-name' title='${file.name}'>${file.name}</td>
|
<td class='file-name' title='${file.name}'>${file.name}</td>
|
||||||
<td class='file-date'>${formatDate(file.modified)}</td>
|
<td class='file-date'>${formatDate(file.modified)}</td>
|
||||||
<td class='file-type'>${file.type}</td>
|
<td class='file-type'>${file.type}</td>
|
||||||
@@ -161,8 +161,8 @@ function renderFiles(files) {
|
|||||||
} else {
|
} else {
|
||||||
files.forEach((file, idx) => {
|
files.forEach((file, idx) => {
|
||||||
let icon = file.type === 'folder'
|
let icon = file.type === 'folder'
|
||||||
? `<i class='fas fa-folder' style='font-size:2.5rem;color:#16767b;'></i>`
|
? `<i class='fas fa-folder' style='font-size:2.5rem;color:var(--primary-color);'></i>`
|
||||||
: `<i class='fas fa-file-alt' style='font-size:2.5rem;color:#741b5f;'></i>`;
|
: `<i class='fas fa-file-alt' style='font-size:2.5rem;color:var(--secondary-color);'></i>`;
|
||||||
let size = file.size !== '-' ? (file.size > 0 ? (file.size < 1024*1024 ? (file.size/1024).toFixed(1)+' KB' : (file.size/1024/1024).toFixed(2)+' MB') : '0 KB') : '-';
|
let size = file.size !== '-' ? (file.size > 0 ? (file.size < 1024*1024 ? (file.size/1024).toFixed(1)+' KB' : (file.size/1024/1024).toFixed(2)+' MB') : '0 KB') : '-';
|
||||||
let actionsArr = [];
|
let actionsArr = [];
|
||||||
let dblClickAction = '';
|
let dblClickAction = '';
|
||||||
@@ -173,12 +173,12 @@ function renderFiles(files) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isTrashPage) {
|
if (isTrashPage) {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Restore' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='event.stopPropagation();restoreFile("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-undo'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Restore' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='event.stopPropagation();restoreFile("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-undo'></i></button>`);
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete Permanently' style='background-color:rgba(220,53,69,0.08);color:#dc3545;' onclick='event.stopPropagation();showPermanentDeleteModal("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-trash'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete Permanently' style='background-color:var(--danger-opacity-15);color:var(--danger-color);' onclick='event.stopPropagation();showPermanentDeleteModal("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-trash'></i></button>`);
|
||||||
} else {
|
} else {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'rgba(255,215,0,0.15)' : 'rgba(22,118,123,0.08)'};color:${file.starred ? '#ffd700' : '#16767b'};' onclick='event.stopPropagation();toggleStar("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-star'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'var(--warning-opacity-15)' : 'var(--primary-opacity-8)'};color:${file.starred ? 'var(--warning-color)' : 'var(--primary-color)'};' onclick='event.stopPropagation();toggleStar("${file.name}", "${file.path}", ${file.room_id})'><i class='fas fa-star'></i></button>`);
|
||||||
}
|
}
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='event.stopPropagation();showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='event.stopPropagation();showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
||||||
const actions = actionsArr.join('');
|
const actions = actionsArr.join('');
|
||||||
grid.innerHTML += `
|
grid.innerHTML += `
|
||||||
<div class='col'>
|
<div class='col'>
|
||||||
@@ -189,7 +189,7 @@ function renderFiles(files) {
|
|||||||
<div class='text-muted small'>${formatDate(file.modified)}</div>
|
<div class='text-muted small'>${formatDate(file.modified)}</div>
|
||||||
<div class='text-muted small'>${size}</div>
|
<div class='text-muted small'>${size}</div>
|
||||||
${isTrashPage ? `<div class='text-muted small'>Auto Delete: ${file.auto_delete ? formatDate(file.auto_delete) : 'Never'}</div>` : ''}
|
${isTrashPage ? `<div class='text-muted small'>Auto Delete: ${file.auto_delete ? formatDate(file.auto_delete) : 'Never'}</div>` : ''}
|
||||||
<div class='mt-2'><button class='btn btn-sm' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='event.stopPropagation();window.location.href="/rooms/${file.room_id}"'><i class='fas fa-door-open me-1'></i>${file.room_name || 'Room ' + file.room_id}</button></div>
|
<div class='mt-2'><button class='btn btn-sm' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='event.stopPropagation();window.location.href="/rooms/${file.room_id}"'><i class='fas fa-door-open me-1'></i>${file.room_name || 'Room ' + file.room_id}</button></div>
|
||||||
</div>
|
</div>
|
||||||
<div class='card-footer bg-white border-0 d-flex justify-content-center gap-2'>${actions}</div>
|
<div class='card-footer bg-white border-0 d-flex justify-content-center gap-2'>${actions}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -428,8 +428,8 @@ function emptyTrash() {
|
|||||||
function showDetailsModal(idx) {
|
function showDetailsModal(idx) {
|
||||||
const item = currentFiles[idx];
|
const item = currentFiles[idx];
|
||||||
const icon = item.type === 'folder'
|
const icon = item.type === 'folder'
|
||||||
? `<i class='fas fa-folder' style='font-size:2.2rem;color:#16767b;'></i>`
|
? `<i class='fas fa-folder' style='font-size:2.2rem;color:var(--primary-color);'></i>`
|
||||||
: `<i class='fas fa-file-alt' style='font-size:2.2rem;color:#741b5f;'></i>`;
|
: `<i class='fas fa-file-alt' style='font-size:2.2rem;color:var(--secondary-color);'></i>`;
|
||||||
const uploaderPic = item.uploader_profile_pic
|
const uploaderPic = item.uploader_profile_pic
|
||||||
? `/uploads/profile_pics/${item.uploader_profile_pic}`
|
? `/uploads/profile_pics/${item.uploader_profile_pic}`
|
||||||
: '/static/default-avatar.png';
|
: '/static/default-avatar.png';
|
||||||
@@ -446,12 +446,12 @@ function showDetailsModal(idx) {
|
|||||||
<span class='fw-semibold' style='font-size:0.98rem;'>${item.uploaded_by || '-'}</span>
|
<span class='fw-semibold' style='font-size:0.98rem;'>${item.uploaded_by || '-'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class='mb-2 text-muted' style='font-size:0.92rem;'><i class='far fa-clock me-1'></i>${formatDate(item.modified)}</div>
|
<div class='mb-2 text-muted' style='font-size:0.92rem;'><i class='far fa-clock me-1'></i>${formatDate(item.modified)}</div>
|
||||||
<hr style='margin:0.7rem 0 0.5rem 0; border-color:#e6f3f4;'>
|
<hr style='margin:0.7rem 0 0.5rem 0; border-color:var(--primary-bg-light);'>
|
||||||
<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Room:</strong> <button class='btn btn-sm' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='window.location.href=\"/room/${item.room_id}\"'><i class='fas fa-door-open me-1'></i>${item.room_name || 'Room ' + item.room_id}</button></div>
|
<div style='font-size:0.91rem;color:var(--text-dark);'><strong style='color:var(--primary-color);'>Room:</strong> <button class='btn btn-sm' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='window.location.href=\"/room/${item.room_id}\"'><i class='fas fa-door-open me-1'></i>${item.room_name || 'Room ' + item.room_id}</button></div>
|
||||||
<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Path:</strong> <span style='word-break:break-all;'>${(item.path ? item.path + '/' : '') + item.name}</span></div>
|
<div style='font-size:0.91rem;color:var(--text-dark);'><strong style='color:var(--primary-color);'>Path:</strong> <span style='word-break:break-all;'>${(item.path ? item.path + '/' : '') + item.name}</span></div>
|
||||||
<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Size:</strong> ${item.size === '-' ? '-' : (item.size > 0 ? (item.size < 1024*1024 ? (item.size/1024).toFixed(1)+' KB' : (item.size/1024/1024).toFixed(2)+' MB') : '0 KB')}</div>
|
<div style='font-size:0.91rem;color:var(--text-dark);'><strong style='color:var(--primary-color);'>Size:</strong> ${item.size === '-' ? '-' : (item.size > 0 ? (item.size < 1024*1024 ? (item.size/1024).toFixed(1)+' KB' : (item.size/1024/1024).toFixed(2)+' MB') : '0 KB')}</div>
|
||||||
<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Uploaded at:</strong> ${item.uploaded_at ? new Date(item.uploaded_at).toLocaleString() : '-'}</div>
|
<div style='font-size:0.91rem;color:var(--text-dark);'><strong style='color:var(--primary-color);'>Uploaded at:</strong> ${item.uploaded_at ? new Date(item.uploaded_at).toLocaleString() : '-'}</div>
|
||||||
${isTrashPage ? `<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Auto Delete:</strong> ${item.auto_delete ? formatDate(item.auto_delete) : 'Never'}</div>` : ''}
|
${isTrashPage ? `<div style='font-size:0.91rem;color:var(--text-dark);'><strong style='color:var(--primary-color);'>Auto Delete:</strong> ${item.auto_delete ? formatDate(item.auto_delete) : 'Never'}</div>` : ''}
|
||||||
`;
|
`;
|
||||||
document.getElementById('detailsModalBody').innerHTML = detailsHtml;
|
document.getElementById('detailsModalBody').innerHTML = detailsHtml;
|
||||||
var modal = new bootstrap.Modal(document.getElementById('detailsModal'));
|
var modal = new bootstrap.Modal(document.getElementById('detailsModal'));
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||||
<link href="{{ url_for('static', filename='css/file-grid.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='css/file-grid.css') }}" rel="stylesheet">
|
||||||
<link href="{{ url_for('static', filename='css/base.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='css/base.css') }}" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/colors.css') }}">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('main.dynamic_colors') }}">
|
||||||
{% block extra_css %}{% endblock %}
|
{% block extra_css %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="mb-0">
|
<h3 class="mb-0">
|
||||||
<i class="fas {{ icon }} me-2" style="color:#16767b;"></i>
|
<i class="fas {{ icon }} me-2" style="color: var(--primary-color);"></i>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h3>
|
</h3>
|
||||||
{% if description %}
|
{% if description %}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
{% if button_url == "#" %}
|
{% if button_url == "#" %}
|
||||||
<button id="emptyTrashBtn"
|
<button id="emptyTrashBtn"
|
||||||
class="btn {{ button_class if button_class else '' }}"
|
class="btn {{ button_class if button_class else '' }}"
|
||||||
style="{{ 'background-color: #16767b; color: white;' if not button_class else '' }}{{ '; ' + button_style if button_style else '' }}">
|
style="{{ 'background-color: var(--primary-color); color: white;' if not button_class else '' }}{{ '; ' + button_style if button_style else '' }}">
|
||||||
{% if button_icon %}
|
{% if button_icon %}
|
||||||
<i class="fas {{ button_icon }} me-1"></i>
|
<i class="fas {{ button_icon }} me-1"></i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<button onclick="window.location.href='{{ button_url }}'"
|
<button onclick="window.location.href='{{ button_url }}'"
|
||||||
class="btn {{ button_class if button_class else '' }}"
|
class="btn {{ button_class if button_class else '' }}"
|
||||||
style="{{ 'background-color: #16767b; color: white;' if not button_class else '' }}{{ '; ' + button_style if button_style else '' }}">
|
style="{{ 'background-color: var(--primary-color); color: white;' if not button_class else '' }}{{ '; ' + button_style if button_style else '' }}">
|
||||||
{% if button_icon %}
|
{% if button_icon %}
|
||||||
<i class="fas {{ button_icon }} me-1"></i>
|
<i class="fas {{ button_icon }} me-1"></i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
{% for type in storage_by_type %}
|
{% for type in storage_by_type %}
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<i class="fas fa-file me-2 icon-primary"></i>
|
<div class="color-indicator me-2" style="width: 12px; height: 12px; border-radius: 50%; background-color: var(--chart-{% if loop.index0 == 0 %}primary{% elif loop.index0 == 1 %}primary-light{% elif loop.index0 == 2 %}primary-lighter{% elif loop.index0 == 3 %}primary-lightest{% elif loop.index0 == 4 %}primary-pale{% elif loop.index0 == 5 %}secondary{% elif loop.index0 == 6 %}secondary-light{% elif loop.index0 == 7 %}secondary-lighter{% elif loop.index0 == 8 %}secondary-lightest{% else %}secondary-pale{% endif %});"></div>
|
||||||
<span class="text-muted">{{ type.extension|upper }}:</span>
|
<span class="text-muted">{{ type.extension|upper }}:</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="fw-bold text-primary">{{ format_size(type.total_size) }}</div>
|
<div class="fw-bold text-primary">{{ format_size(type.total_size) }}</div>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{% for type in trash_by_type %}
|
{% for type in trash_by_type %}
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<i class="fas fa-file me-2 icon-primary"></i>
|
<div class="color-indicator me-2" style="width: 12px; height: 12px; border-radius: 50%; background-color: var(--chart-{% if loop.index0 == 0 %}primary{% elif loop.index0 == 1 %}primary-light{% elif loop.index0 == 2 %}primary-lighter{% elif loop.index0 == 3 %}primary-lightest{% elif loop.index0 == 4 %}primary-pale{% elif loop.index0 == 5 %}secondary{% elif loop.index0 == 6 %}secondary-light{% elif loop.index0 == 7 %}secondary-lighter{% elif loop.index0 == 8 %}secondary-lightest{% else %}secondary-pale{% endif %});"></div>
|
||||||
<span class="text-muted">{{ type.extension|upper }}:</span>
|
<span class="text-muted">{{ type.extension|upper }}:</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="fw-bold text-primary">{{ type.count }}</div>
|
<div class="fw-bold text-primary">{{ type.count }}</div>
|
||||||
|
|||||||
@@ -41,9 +41,9 @@
|
|||||||
<option value="user" {% if request.args.get('role') == 'user' %}selected{% endif %}>User</option>
|
<option value="user" {% if request.args.get('role') == 'user' %}selected{% endif %}>User</option>
|
||||||
</select>
|
</select>
|
||||||
<button type="button" id="clearFilters" class="px-4 py-2 rounded-lg text-white font-medium transition-colors duration-200"
|
<button type="button" id="clearFilters" class="px-4 py-2 rounded-lg text-white font-medium transition-colors duration-200"
|
||||||
style="background-color: #16767b; border: 1px solid #16767b;"
|
style="background-color: var(--primary-color); border: 1px solid var(--primary-color);"
|
||||||
onmouseover="this.style.backgroundColor='#1a8a90'"
|
onmouseover="this.style.backgroundColor='var(--primary-light)'"
|
||||||
onmouseout="this.style.backgroundColor='#16767b'">
|
onmouseout="this.style.backgroundColor='var(--primary-color)'">
|
||||||
Clear
|
Clear
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -132,14 +132,14 @@
|
|||||||
<div class="flex flex-row flex-wrap gap-1.5">
|
<div class="flex flex-row flex-wrap gap-1.5">
|
||||||
<a href="mailto:{{ user.email }}"
|
<a href="mailto:{{ user.email }}"
|
||||||
class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-sm no-underline transition-colors duration-200"
|
class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-sm no-underline transition-colors duration-200"
|
||||||
style="background-color: rgba(22,118,123,0.08); color: #16767b;">
|
style="background-color: var(--primary-opacity-8); color: var(--primary-color);">
|
||||||
<i class="fas fa-envelope" style="font-size: 0.85em; opacity: 0.7;"></i>
|
<i class="fas fa-envelope" style="font-size: 0.85em; opacity: 0.7;"></i>
|
||||||
{{ user.email }}
|
{{ user.email }}
|
||||||
</a>
|
</a>
|
||||||
{% if user.phone %}
|
{% if user.phone %}
|
||||||
<a href="tel:{{ user.phone }}"
|
<a href="tel:{{ user.phone }}"
|
||||||
class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-sm no-underline transition-colors duration-200"
|
class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-sm no-underline transition-colors duration-200"
|
||||||
style="background-color: rgba(22,118,123,0.08); color: #16767b;">
|
style="background-color: var(--primary-opacity-8); color: var(--primary-color);">
|
||||||
<i class="fas fa-phone" style="font-size: 0.85em; opacity: 0.7;"></i>
|
<i class="fas fa-phone" style="font-size: 0.85em; opacity: 0.7;"></i>
|
||||||
{{ user.phone }}
|
{{ user.phone }}
|
||||||
</a>
|
</a>
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
<div class="flex justify-end gap-1.5">
|
<div class="flex justify-end gap-1.5">
|
||||||
<a href="{{ url_for('contacts.edit_contact', id=user.id) }}"
|
<a href="{{ url_for('contacts.edit_contact', id=user.id) }}"
|
||||||
class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-sm no-underline transition-colors duration-200"
|
class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-sm no-underline transition-colors duration-200"
|
||||||
style="background-color: rgba(22,118,123,0.08); color: #16767b;">
|
style="background-color: var(--primary-opacity-8); color: var(--primary-color);">
|
||||||
<i class="fas fa-edit" style="font-size: 0.85em; opacity: 0.7;"></i>
|
<i class="fas fa-edit" style="font-size: 0.85em; opacity: 0.7;"></i>
|
||||||
Edit
|
Edit
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css') }}">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('main.dynamic_colors') }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -31,28 +31,28 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-2" id="actionButtonsRow">
|
<div class="d-flex gap-2" id="actionButtonsRow">
|
||||||
{% if current_user.is_admin %}
|
{% if current_user.is_admin %}
|
||||||
<a href="{{ url_for('rooms.room_members', room_id=room.id) }}" class="btn btn-outline-primary d-flex align-items-center gap-2" style="border-color:#16767b; color:#16767b;" onmouseover="this.style.backgroundColor='#16767b'; this.style.color='white'" onmouseout="this.style.backgroundColor='transparent'; this.style.color='#16767b'">
|
<a href="{{ url_for('rooms.room_members', room_id=room.id) }}" class="btn btn-outline-primary d-flex align-items-center gap-2" style="border-color:var(--primary-color); color:var(--primary-color);" onmouseover="this.style.backgroundColor='var(--primary-color)'; this.style.color='white'" onmouseout="this.style.backgroundColor='transparent'; this.style.color='var(--primary-color)'">
|
||||||
<i class="fas fa-users"></i> Manage Members
|
<i class="fas fa-users"></i> Manage Members
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if current_user.is_admin or can_upload %}
|
{% if current_user.is_admin or can_upload %}
|
||||||
<button type="button" id="newFolderBtn" class="btn btn-outline-primary d-flex align-items-center gap-2" style="border-color:#16767b; color:#16767b;" onmouseover="this.style.backgroundColor='#16767b'; this.style.color='white'" onmouseout="this.style.backgroundColor='transparent'; this.style.color='#16767b'">
|
<button type="button" id="newFolderBtn" class="btn btn-outline-primary d-flex align-items-center gap-2" style="border-color:var(--primary-color); color:var(--primary-color);" onmouseover="this.style.backgroundColor='var(--primary-color)'; this.style.color='white'" onmouseout="this.style.backgroundColor='transparent'; this.style.color='var(--primary-color)'">
|
||||||
<i class="fas fa-folder-plus"></i> New Folder
|
<i class="fas fa-folder-plus"></i> New Folder
|
||||||
</button>
|
</button>
|
||||||
<form id="uploadForm" enctype="multipart/form-data" class="d-inline">
|
<form id="uploadForm" enctype="multipart/form-data" class="d-inline">
|
||||||
<input type="file" id="fileInput" name="file" multiple style="display:none;" />
|
<input type="file" id="fileInput" name="file" multiple style="display:none;" />
|
||||||
<button type="button" id="uploadBtn" class="btn btn-primary d-flex align-items-center gap-2" style="background-color:#16767b; border:1px solid #16767b;" onmouseover="this.style.backgroundColor='#1a8a90'" onmouseout="this.style.backgroundColor='#16767b'">
|
<button type="button" id="uploadBtn" class="btn btn-primary d-flex align-items-center gap-2" style="background-color:var(--primary-color); border:1px solid var(--primary-color);" onmouseover="this.style.backgroundColor='var(--primary-light)'" onmouseout="this.style.backgroundColor='var(--primary-color)'">
|
||||||
<i class="fas fa-upload"></i> Upload
|
<i class="fas fa-upload"></i> Upload
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if current_user.is_admin or can_download %}
|
{% if current_user.is_admin or can_download %}
|
||||||
<button id="downloadSelectedBtn" class="btn btn-outline-primary btn-sm d-flex align-items-center gap-2" style="display:none; border-color:#16767b; color:#16767b;" onmouseover="this.style.backgroundColor='#16767b'; this.style.color='white'" onmouseout="this.style.backgroundColor='transparent'; this.style.color='#16767b'">
|
<button id="downloadSelectedBtn" class="btn btn-outline-primary btn-sm d-flex align-items-center gap-2" style="display:none; border-color:var(--primary-color); color:var(--primary-color);" onmouseover="this.style.backgroundColor='var(--primary-color)'; this.style.color='white'" onmouseout="this.style.backgroundColor='transparent'; this.style.color='var(--primary-color)'">
|
||||||
<i class="fas fa-download"></i> Download Selected
|
<i class="fas fa-download"></i> Download Selected
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if current_user.is_admin or can_delete %}
|
{% if current_user.is_admin or can_delete %}
|
||||||
<button id="deleteSelectedBtn" class="btn btn-outline-danger btn-sm d-flex align-items-center gap-2" style="display:none; border-color:#b91c1c; color:#b91c1c;" onmouseover="this.style.backgroundColor='#b91c1c'; this.style.color='white'" onmouseout="this.style.backgroundColor='transparent'; this.style.color='#b91c1c'">
|
<button id="deleteSelectedBtn" class="btn btn-outline-danger btn-sm d-flex align-items-center gap-2" style="display:none; border-color:var(--danger-color); color:var(--danger-color);" onmouseover="this.style.backgroundColor='var(--danger-color)'; this.style.color='white'" onmouseout="this.style.backgroundColor='transparent'; this.style.color='var(--danger-color)'">
|
||||||
<i class="fas fa-trash"></i> Delete Selected
|
<i class="fas fa-trash"></i> Delete Selected
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -60,8 +60,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div id="uploadProgressContainer" style="display:none; margin-bottom: 1rem; width: 100%;">
|
<div id="uploadProgressContainer" style="display:none; margin-bottom: 1rem; width: 100%;">
|
||||||
<div class="progress" style="height: 1.25rem; background-color: #e6f3f4;">
|
<div class="progress" style="height: 1.25rem; background-color: var(--primary-bg-light);">
|
||||||
<div id="uploadProgressBar" class="progress-bar" role="progressbar" style="width:0%; background-color:#16767b; color:#fff;">0%</div>
|
<div id="uploadProgressBar" class="progress-bar" role="progressbar" style="width:0%; background-color:var(--primary-color); color:var(--white);">0%</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="uploadProgressText" class="small text-muted mt-1"></div>
|
<div id="uploadProgressText" class="small text-muted mt-1"></div>
|
||||||
<div id="uploadError" class="alert alert-danger alert-dismissible fade show mt-2" style="display:none;" role="alert">
|
<div id="uploadError" class="alert alert-danger alert-dismissible fade show mt-2" style="display:none;" role="alert">
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="d-flex align-items-center gap-3 mb-3">
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
<i class="fas fa-trash text-danger" style="font-size: 2rem;"></i>
|
<i class="fas fa-trash" style="font-size: 2rem; color: var(--danger-color);"></i>
|
||||||
<div>
|
<div>
|
||||||
<h6 class="mb-1">Move to Trash</h6>
|
<h6 class="mb-1">Move to Trash</h6>
|
||||||
<p class="text-muted mb-0" id="deleteFileName"></p>
|
<p class="text-muted mb-0" id="deleteFileName"></p>
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
<button type="button" class="btn btn-danger" id="confirmDeleteBtn" style="background-color: #b91c1c; border-color: #b91c1c;">
|
<button type="button" class="btn btn-danger" id="confirmDeleteBtn" style="background-color: var(--danger-color); border-color: var(--danger-color);">
|
||||||
<i class="fas fa-trash me-1"></i>Move to Trash
|
<i class="fas fa-trash me-1"></i>Move to Trash
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
<button type="button" class="btn btn-primary" id="createFolderBtn" style="background-color: #16767b; border-color: #16767b;">Create</button>
|
<button type="button" class="btn btn-primary" id="createFolderBtn" style="background-color: var(--primary-color); border-color: var(--primary-color);">Create</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
<button type="button" class="btn btn-primary" id="confirmRenameBtn" style="background-color: #16767b; border-color: #16767b;">Rename</button>
|
<button type="button" class="btn btn-primary" id="confirmRenameBtn" style="background-color: var(--primary-color); border-color: var(--primary-color);">Rename</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -191,8 +191,8 @@
|
|||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" id="skipOverwriteBtn">Skip</button>
|
<button type="button" class="btn btn-secondary" id="skipOverwriteBtn">Skip</button>
|
||||||
<button type="button" class="btn btn-secondary" id="skipAllOverwriteBtn">Skip All</button>
|
<button type="button" class="btn btn-secondary" id="skipAllOverwriteBtn">Skip All</button>
|
||||||
<button type="button" class="btn btn-danger" id="confirmOverwriteBtn" style="background-color: #b91c1c; border-color: #b91c1c;">Overwrite</button>
|
<button type="button" class="btn btn-danger" id="confirmOverwriteBtn" style="background-color: var(--danger-color); border-color: var(--danger-color);">Overwrite</button>
|
||||||
<button type="button" class="btn btn-danger" id="confirmAllOverwriteBtn" style="background-color: #b91c1c; border-color: #b91c1c;">Overwrite All</button>
|
<button type="button" class="btn btn-danger" id="confirmAllOverwriteBtn" style="background-color: var(--danger-color); border-color: var(--danger-color);">Overwrite All</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -217,7 +217,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
<button type="button" class="btn btn-primary" id="confirmMoveBtn" style="background-color:#16767b; border:1px solid #16767b;">Move</button>
|
<button type="button" class="btn btn-primary" id="confirmMoveBtn" style="background-color: var(--primary-color); border-color: var(--primary-color);">Move</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -270,22 +270,22 @@
|
|||||||
#fileGrid.list-view table {
|
#fileGrid.list-view table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
background: #fff;
|
background: var(--white);
|
||||||
}
|
}
|
||||||
#fileGrid.list-view th, #fileGrid.list-view td {
|
#fileGrid.list-view th, #fileGrid.list-view td {
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
border-bottom: 1px solid #e9ecef;
|
border-bottom: 1px solid var(--border-light);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
#fileGrid.list-view th {
|
#fileGrid.list-view th {
|
||||||
background: #f8f9fa;
|
background: var(--bg-color);
|
||||||
color: #6c757d;
|
color: var(--text-muted);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
#fileGrid.list-view tr:hover td {
|
#fileGrid.list-view tr:hover td {
|
||||||
background-color: rgba(22, 118, 123, 0.08);
|
background-color: var(--primary-opacity-8);
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
}
|
}
|
||||||
#fileGrid.list-view .file-icon {
|
#fileGrid.list-view .file-icon {
|
||||||
@@ -308,31 +308,31 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 40px 2fr 1fr 1fr 1fr;
|
grid-template-columns: 40px 2fr 1fr 1fr 1fr;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
background-color: #f8f9fa;
|
background-color: var(--bg-color);
|
||||||
border-bottom: 1px solid #e9ecef;
|
border-bottom: 1px solid var(--border-light);
|
||||||
color: #6c757d;
|
color: var(--text-muted);
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
.btn-group.btn-group-sm .btn {
|
.btn-group.btn-group-sm .btn {
|
||||||
background-color: #fff;
|
background-color: var(--white);
|
||||||
border-color: #e9ecef;
|
border-color: var(--border-light);
|
||||||
color: #6c757d;
|
color: var(--text-muted);
|
||||||
transition: background-color 0.15s, color 0.15s;
|
transition: background-color 0.15s, color 0.15s;
|
||||||
}
|
}
|
||||||
.btn-group.btn-group-sm .btn.active, .btn-group.btn-group-sm .btn:active {
|
.btn-group.btn-group-sm .btn.active, .btn-group.btn-group-sm .btn:active {
|
||||||
background-color: #e6f3f4 !important;
|
background-color: var(--primary-bg-light) !important;
|
||||||
color: #16767b !important;
|
color: var(--primary-color) !important;
|
||||||
border-color: #16767b !important;
|
border-color: var(--primary-color) !important;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
.btn-group.btn-group-sm .btn:focus {
|
.btn-group.btn-group-sm .btn:focus {
|
||||||
box-shadow: 0 0 0 0.1rem #16767b33;
|
box-shadow: 0 0 0 0.1rem var(--primary-opacity-20);
|
||||||
}
|
}
|
||||||
.btn-group.btn-group-sm .btn:hover:not(.active) {
|
.btn-group.btn-group-sm .btn:hover:not(.active) {
|
||||||
background-color: #f8f9fa;
|
background-color: var(--bg-color);
|
||||||
color: #16767b;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
#fileGrid.table-mode {
|
#fileGrid.table-mode {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -340,22 +340,22 @@
|
|||||||
#fileGrid.table-mode table {
|
#fileGrid.table-mode table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
background: #fff;
|
background: var(--white);
|
||||||
}
|
}
|
||||||
#fileGrid.table-mode th, #fileGrid.table-mode td {
|
#fileGrid.table-mode th, #fileGrid.table-mode td {
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
border-bottom: 1px solid #e9ecef;
|
border-bottom: 1px solid var(--border-light);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
#fileGrid.table-mode th {
|
#fileGrid.table-mode th {
|
||||||
background: #f8f9fa;
|
background: var(--bg-color);
|
||||||
color: #6c757d;
|
color: var(--text-muted);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
#fileGrid.table-mode tr:hover td {
|
#fileGrid.table-mode tr:hover td {
|
||||||
background-color: rgba(22, 118, 123, 0.08);
|
background-color: var(--primary-opacity-8);
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
}
|
}
|
||||||
#fileGrid.table-mode .file-icon {
|
#fileGrid.table-mode .file-icon {
|
||||||
@@ -374,6 +374,9 @@
|
|||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
margin-left: 0.25rem;
|
margin-left: 0.25rem;
|
||||||
}
|
}
|
||||||
|
#fileGrid.table-mode tr.selected {
|
||||||
|
background-color: var(--primary-bg-light) !important;
|
||||||
|
}
|
||||||
/* Disable text selection for file grid and table rows/cards */
|
/* Disable text selection for file grid and table rows/cards */
|
||||||
#fileGrid, #fileGrid * {
|
#fileGrid, #fileGrid * {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -490,8 +493,8 @@ function showDetailsModal(idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const icon = item.type === 'folder'
|
const icon = item.type === 'folder'
|
||||||
? `<i class='fas fa-folder' style='font-size:2.2rem;color:#16767b;'></i>`
|
? `<i class='fas fa-folder' style='font-size:2.2rem;color:var(--primary-color);'></i>`
|
||||||
: `<i class='fas fa-file-alt' style='font-size:2.2rem;color:#741b5f;'></i>`;
|
: `<i class='fas fa-file-alt' style='font-size:2.2rem;color:var(--secondary-color);'></i>`;
|
||||||
const uploaderPic = item.uploader_profile_pic
|
const uploaderPic = item.uploader_profile_pic
|
||||||
? `/uploads/profile_pics/${item.uploader_profile_pic}`
|
? `/uploads/profile_pics/${item.uploader_profile_pic}`
|
||||||
: '/static/default-avatar.png';
|
: '/static/default-avatar.png';
|
||||||
@@ -513,11 +516,11 @@ function showDetailsModal(idx) {
|
|||||||
<span class='fw-semibold' style='font-size:0.98rem;'>${item.uploaded_by || '-'}</span>
|
<span class='fw-semibold' style='font-size:0.98rem;'>${item.uploaded_by || '-'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class='mb-2 text-muted' style='font-size:0.92rem;'><i class='far fa-clock me-1'></i>${formatDate(item.modified)}</div>
|
<div class='mb-2 text-muted' style='font-size:0.92rem;'><i class='far fa-clock me-1'></i>${formatDate(item.modified)}</div>
|
||||||
<hr style='margin:0.7rem 0 0.5rem 0; border-color:#e6f3f4;'>
|
<hr style='margin:0.7rem 0 0.5rem 0; border-color:var(--border-light);'>
|
||||||
<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Room:</strong> <button class='btn btn-sm' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='window.location.href=\"/room/${roomId}\"'><i class='fas fa-door-open me-1'></i>${roomName}</button></div>
|
<div style='font-size:0.91rem;color:var(--text-muted);'><strong style='color:var(--primary-color);'>Room:</strong> <button class='btn btn-sm' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='window.location.href=\"/room/${roomId}\"'><i class='fas fa-door-open me-1'></i>${roomName}</button></div>
|
||||||
<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Path:</strong> <span style='word-break:break-all;'>${(item.path ? item.path + '/' : '') + item.name}</span></div>
|
<div style='font-size:0.91rem;color:var(--text-muted);'><strong style='color:var(--primary-color);'>Path:</strong> <span style='word-break:break-all;'>${(item.path ? item.path + '/' : '') + item.name}</span></div>
|
||||||
<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Size:</strong> ${item.size === '-' ? '-' : (item.size > 0 ? (item.size < 1024*1024 ? (item.size/1024).toFixed(1)+' KB' : (item.size/1024/1024).toFixed(2)+' MB') : '0 KB')}</div>
|
<div style='font-size:0.91rem;color:var(--text-muted);'><strong style='color:var(--primary-color);'>Size:</strong> ${item.size === '-' ? '-' : (item.size > 0 ? (item.size < 1024*1024 ? (item.size/1024).toFixed(1)+' KB' : (item.size/1024/1024).toFixed(2)+' MB') : '0 KB')}</div>
|
||||||
<div style='font-size:0.91rem;color:#555;'><strong style='color:#16767b;'>Uploaded at:</strong> ${item.uploaded_at ? new Date(item.uploaded_at).toLocaleString() : '-'}</div>
|
<div style='font-size:0.91rem;color:var(--text-muted);'><strong style='color:var(--primary-color);'>Uploaded at:</strong> ${item.uploaded_at ? new Date(item.uploaded_at).toLocaleString() : '-'}</div>
|
||||||
`;
|
`;
|
||||||
document.getElementById('detailsModalBody').innerHTML = detailsHtml;
|
document.getElementById('detailsModalBody').innerHTML = detailsHtml;
|
||||||
var modal = new bootstrap.Modal(document.getElementById('detailsModal'));
|
var modal = new bootstrap.Modal(document.getElementById('detailsModal'));
|
||||||
@@ -589,10 +592,10 @@ function renderBreadcrumb() {
|
|||||||
bc.innerHTML = '';
|
bc.innerHTML = '';
|
||||||
const parts = currentPath ? currentPath.split('/') : [];
|
const parts = currentPath ? currentPath.split('/') : [];
|
||||||
let pathSoFar = '';
|
let pathSoFar = '';
|
||||||
bc.innerHTML += `<a href="#" onclick="navigateTo('')" class="text-decoration-none" style="color:#16767b;">Root</a>`;
|
bc.innerHTML += `<a href="#" onclick="navigateTo('')" class="text-decoration-none" style="color:var(--primary-color);">Root</a>`;
|
||||||
parts.forEach((part, idx) => {
|
parts.forEach((part, idx) => {
|
||||||
pathSoFar += (pathSoFar ? '/' : '') + part;
|
pathSoFar += (pathSoFar ? '/' : '') + part;
|
||||||
bc.innerHTML += ` <span class="text-muted">/</span> <a href="#" onclick="navigateTo('${pathSoFar}')" class="text-decoration-none" style="color:#16767b;">${part}</a>`;
|
bc.innerHTML += ` <span class="text-muted">/</span> <a href="#" onclick="navigateTo('${pathSoFar}')" class="text-decoration-none" style="color:var(--primary-color);">${part}</a>`;
|
||||||
});
|
});
|
||||||
// Show/hide up button
|
// Show/hide up button
|
||||||
const upBtn = document.getElementById('upBtn');
|
const upBtn = document.getElementById('upBtn');
|
||||||
@@ -723,8 +726,8 @@ function renderFiles(files) {
|
|||||||
</tr></thead><tbody>`;
|
</tr></thead><tbody>`;
|
||||||
filesToRender.forEach((file, idx) => {
|
filesToRender.forEach((file, idx) => {
|
||||||
let icon = file.type === 'folder'
|
let icon = file.type === 'folder'
|
||||||
? `<i class='fas fa-folder' style='font-size:1.5rem;color:#16767b;'></i>`
|
? `<i class='fas fa-folder' style='font-size:1.5rem;color:var(--primary-color);'></i>`
|
||||||
: `<i class='fas fa-file-alt' style='font-size:1.5rem;color:#741b5f;'></i>`;
|
: `<i class='fas fa-file-alt' style='font-size:1.5rem;color:var(--secondary-color);'></i>`;
|
||||||
let size = file.size !== '-' ? (file.size > 0 ? (file.size < 1024*1024 ? (file.size/1024).toFixed(1)+' KB' : (file.size/1024/1024).toFixed(2)+' MB') : '0 KB') : '-';
|
let size = file.size !== '-' ? (file.size > 0 ? (file.size < 1024*1024 ? (file.size/1024).toFixed(1)+' KB' : (file.size/1024/1024).toFixed(2)+' MB') : '0 KB') : '-';
|
||||||
let actionsArr = [];
|
let actionsArr = [];
|
||||||
const canRenameAction = (canRename === 'true');
|
const canRenameAction = (canRename === 'true');
|
||||||
@@ -737,28 +740,28 @@ function renderFiles(files) {
|
|||||||
}
|
}
|
||||||
if (file.type === 'file') {
|
if (file.type === 'file') {
|
||||||
if (canDownload === 'true') {
|
if (canDownload === 'true') {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Download' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='downloadFile("${file.name}")'><i class='fas fa-download'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Download' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='downloadFile("${file.name}")'><i class='fas fa-download'></i></button>`);
|
||||||
}
|
}
|
||||||
if (canRenameAction) {
|
if (canRenameAction) {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Rename' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showRenameModal("${file.name}")'><i class='fas fa-pen'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Rename' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showRenameModal("${file.name}")'><i class='fas fa-pen'></i></button>`);
|
||||||
}
|
}
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
||||||
if (canMove === 'true') {
|
if (canMove === 'true') {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Move' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showMoveModal("${file.name}", "${file.path}")'><i class='fas fa-arrows-alt'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Move' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showMoveModal("${file.name}", "${file.path}")'><i class='fas fa-arrows-alt'></i></button>`);
|
||||||
}
|
}
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'rgba(255,215,0,0.15)' : 'rgba(22,118,123,0.08)'};color:${file.starred ? '#ffd700' : '#16767b'};' onclick='event.stopPropagation(); toggleStar("${file.name}", "${file.path || ''}")'><i class='fas fa-star'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'var(--warning-opacity-15)' : 'var(--primary-opacity-8)'};color:${file.starred ? 'var(--warning-color)' : 'var(--primary-color)'};' onclick='event.stopPropagation(); toggleStar("${file.name}", "${file.path || ''}")'><i class='fas fa-star'></i></button>`);
|
||||||
if (canDelete === true || canDelete === 'true') {
|
if (canDelete === true || canDelete === 'true') {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete' style='background-color:rgba(239,68,68,0.1);color:#b91c1c;' onclick='showDeleteModal("${file.name}", "${file.path}")'><i class='fas fa-trash'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete' style='background-color:var(--danger-opacity-15);color:var(--danger-color);' onclick='showDeleteModal("${file.name}", "${file.path}")'><i class='fas fa-trash'></i></button>`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Open Folder' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='navigateTo(\"${currentPath ? currentPath + '/' : ''}${file.name}\")'><i class='fas fa-folder-open'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Open Folder' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='navigateTo(\"${currentPath ? currentPath + '/' : ''}${file.name}\")'><i class='fas fa-folder-open'></i></button>`);
|
||||||
if (canRenameAction) {
|
if (canRenameAction) {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Rename' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showRenameModal(\"${file.name}\")'><i class='fas fa-pen'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Rename' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showRenameModal(\"${file.name}\")'><i class='fas fa-pen'></i></button>`);
|
||||||
}
|
}
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'rgba(255,215,0,0.15)' : 'rgba(22,118,123,0.08)'};color:${file.starred ? '#ffd700' : '#16767b'};' onclick='event.stopPropagation(); toggleStar("${file.name}", "${file.path || ''}")'><i class='fas fa-star'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'var(--warning-opacity-15)' : 'var(--primary-opacity-8)'};color:${file.starred ? 'var(--warning-color)' : 'var(--primary-color)'};' onclick='event.stopPropagation(); toggleStar("${file.name}", "${file.path || ''}")'><i class='fas fa-star'></i></button>`);
|
||||||
if (canDelete === true || canDelete === 'true') {
|
if (canDelete === true || canDelete === 'true') {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete' style='background-color:rgba(239,68,68,0.1);color:#b91c1c;' onclick='showDeleteModal("${file.name}", "${file.path}")'><i class='fas fa-trash'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete' style='background-color:var(--danger-opacity-15);color:var(--danger-color);' onclick='showDeleteModal("${file.name}", "${file.path}")'><i class='fas fa-trash'></i></button>`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Move Delete to the end if present
|
// Move Delete to the end if present
|
||||||
@@ -806,28 +809,28 @@ function renderFiles(files) {
|
|||||||
}
|
}
|
||||||
if (file.type === 'file') {
|
if (file.type === 'file') {
|
||||||
if (canDownload === 'true') {
|
if (canDownload === 'true') {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Download' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='downloadFile("${file.name}")'><i class='fas fa-download'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Download' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='downloadFile("${file.name}")'><i class='fas fa-download'></i></button>`);
|
||||||
}
|
}
|
||||||
if (canRenameAction) {
|
if (canRenameAction) {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Rename' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showRenameModal("${file.name}")'><i class='fas fa-pen'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Rename' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showRenameModal("${file.name}")'><i class='fas fa-pen'></i></button>`);
|
||||||
}
|
}
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
||||||
if (canMove === 'true') {
|
if (canMove === 'true') {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Move' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showMoveModal("${file.name}", "${file.path}")'><i class='fas fa-arrows-alt'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Move' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showMoveModal("${file.name}", "${file.path}")'><i class='fas fa-arrows-alt'></i></button>`);
|
||||||
}
|
}
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'rgba(255,215,0,0.15)' : 'rgba(22,118,123,0.08)'};color:${file.starred ? '#ffd700' : '#16767b'};' onclick='event.stopPropagation(); toggleStar("${file.name}", "${file.path || ''}")'><i class='fas fa-star'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'var(--warning-opacity-15)' : 'var(--primary-opacity-8)'};color:${file.starred ? 'var(--warning-color)' : 'var(--primary-color)'};' onclick='event.stopPropagation(); toggleStar("${file.name}", "${file.path || ''}")'><i class='fas fa-star'></i></button>`);
|
||||||
if (canDelete === true || canDelete === 'true') {
|
if (canDelete === true || canDelete === 'true') {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete' style='background-color:rgba(239,68,68,0.1);color:#b91c1c;' onclick='showDeleteModal("${file.name}", "${file.path}")'><i class='fas fa-trash'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete' style='background-color:var(--danger-opacity-15);color:var(--danger-color);' onclick='showDeleteModal("${file.name}", "${file.path}")'><i class='fas fa-trash'></i></button>`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Open Folder' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='navigateTo(\"${currentPath ? currentPath + '/' : ''}${file.name}\")'><i class='fas fa-folder-open'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Open Folder' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='navigateTo(\"${currentPath ? currentPath + '/' : ''}${file.name}\")'><i class='fas fa-folder-open'></i></button>`);
|
||||||
if (canRenameAction) {
|
if (canRenameAction) {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Rename' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showRenameModal(\"${file.name}\")'><i class='fas fa-pen'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Rename' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showRenameModal(\"${file.name}\")'><i class='fas fa-pen'></i></button>`);
|
||||||
}
|
}
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:rgba(22,118,123,0.08);color:#16767b;' onclick='showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Details' style='background-color:var(--primary-opacity-8);color:var(--primary-color);' onclick='showDetailsModal(${idx})'><i class='fas fa-info-circle'></i></button>`);
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'rgba(255,215,0,0.15)' : 'rgba(22,118,123,0.08)'};color:${file.starred ? '#ffd700' : '#16767b'};' onclick='event.stopPropagation(); toggleStar("${file.name}", "${file.path || ''}")'><i class='fas fa-star'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='${file.starred ? 'Unstar' : 'Star'}' style='background-color:${file.starred ? 'var(--warning-opacity-15)' : 'var(--primary-opacity-8)'};color:${file.starred ? 'var(--warning-color)' : 'var(--primary-color)'};' onclick='event.stopPropagation(); toggleStar("${file.name}", "${file.path || ''}")'><i class='fas fa-star'></i></button>`);
|
||||||
if (canDelete === true || canDelete === 'true') {
|
if (canDelete === true || canDelete === 'true') {
|
||||||
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete' style='background-color:rgba(239,68,68,0.1);color:#b91c1c;' onclick='showDeleteModal("${file.name}", "${file.path}")'><i class='fas fa-trash'></i></button>`);
|
actionsArr.push(`<button class='btn btn-sm file-action-btn' title='Delete' style='background-color:var(--danger-opacity-15);color:var(--danger-color);' onclick='showDeleteModal("${file.name}", "${file.path}")'><i class='fas fa-trash'></i></button>`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Move Delete to the end if present
|
// Move Delete to the end if present
|
||||||
|
|||||||
@@ -25,9 +25,9 @@
|
|||||||
<form method="GET" class="d-flex align-items-center w-100 justify-content-between" id="roomFilterForm" style="gap: 1rem;">
|
<form method="GET" class="d-flex align-items-center w-100 justify-content-between" id="roomFilterForm" style="gap: 1rem;">
|
||||||
<input type="text" name="search" placeholder="Search rooms..." value="{{ search }}" class="form-control flex-grow-1" id="roomSearchInput" autocomplete="off" style="min-width: 0;" />
|
<input type="text" name="search" placeholder="Search rooms..." value="{{ search }}" class="form-control flex-grow-1" id="roomSearchInput" autocomplete="off" style="min-width: 0;" />
|
||||||
<button type="button" id="clearRoomsFilter" class="px-4 py-2 rounded-lg text-white font-medium transition-colors duration-200 ms-2 flex-shrink-0"
|
<button type="button" id="clearRoomsFilter" class="px-4 py-2 rounded-lg text-white font-medium transition-colors duration-200 ms-2 flex-shrink-0"
|
||||||
style="background-color: #16767b; border: 1px solid #16767b;"
|
style="background-color: var(--primary-color); border: 1px solid var(--primary-color);"
|
||||||
onmouseover="this.style.backgroundColor='#1a8a90'"
|
onmouseover="this.style.backgroundColor='var(--primary-light)'"
|
||||||
onmouseout="this.style.backgroundColor='#16767b'">
|
onmouseout="this.style.backgroundColor='var(--primary-color)'">
|
||||||
Clear
|
Clear
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -13,6 +13,316 @@
|
|||||||
) }}
|
) }}
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!-- Settings content will go here -->
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5 class="card-title mb-0">Theme Colors</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form id="colorSettingsForm" method="POST" action="{{ url_for('main.update_colors') }}">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||||
|
|
||||||
|
<!-- Primary Color Section -->
|
||||||
|
<div class="mb-5">
|
||||||
|
<h6 class="mb-3">Primary Color</h6>
|
||||||
|
<div class="row g-4">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<label class="form-label">Main Color</label>
|
||||||
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
|
<input type="color"
|
||||||
|
class="form-control form-control-color d-none"
|
||||||
|
id="primaryColor"
|
||||||
|
name="primary_color"
|
||||||
|
value="{{ primary_color }}"
|
||||||
|
data-original-value="{{ primary_color }}">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-outline-secondary"
|
||||||
|
onclick="document.getElementById('primaryColor').click()">
|
||||||
|
<i class="fas fa-palette me-1"></i> Choose Color
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Used for primary buttons, links, and accents</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<label class="form-label">Derived Colors</label>
|
||||||
|
<div class="d-flex gap-3" id="primaryDerivedColors">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="color-preview p-3 rounded shadow-sm mb-2"
|
||||||
|
data-color-type="base"
|
||||||
|
style="background-color: var(--primary-color); width: 80px; height: 80px;">
|
||||||
|
</div>
|
||||||
|
<small class="d-block text-muted">Base</small>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="color-preview p-3 rounded shadow-sm mb-2"
|
||||||
|
data-color-type="light"
|
||||||
|
style="background-color: var(--primary-light); width: 80px; height: 80px;">
|
||||||
|
</div>
|
||||||
|
<small class="d-block text-muted">Light</small>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="color-preview p-3 rounded shadow-sm mb-2"
|
||||||
|
data-color-type="bg-light"
|
||||||
|
style="background-color: var(--primary-bg-light); width: 80px; height: 80px;">
|
||||||
|
</div>
|
||||||
|
<small class="d-block text-muted">Background</small>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="color-preview p-3 rounded shadow-sm mb-2"
|
||||||
|
data-color-type="opacity"
|
||||||
|
style="background-color: var(--primary-opacity-15); width: 80px; height: 80px;">
|
||||||
|
</div>
|
||||||
|
<small class="d-block text-muted">Opacity 15%</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Secondary Color Section -->
|
||||||
|
<div class="mb-5">
|
||||||
|
<h6 class="mb-3">Secondary Color</h6>
|
||||||
|
<div class="row g-4">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<label class="form-label">Main Color</label>
|
||||||
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
|
<input type="color"
|
||||||
|
class="form-control form-control-color d-none"
|
||||||
|
id="secondaryColor"
|
||||||
|
name="secondary_color"
|
||||||
|
value="{{ secondary_color }}"
|
||||||
|
data-original-value="{{ secondary_color }}">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-outline-secondary"
|
||||||
|
onclick="document.getElementById('secondaryColor').click()">
|
||||||
|
<i class="fas fa-palette me-1"></i> Choose Color
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Used for secondary elements and highlights</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<label class="form-label">Derived Colors</label>
|
||||||
|
<div class="d-flex gap-3" id="secondaryDerivedColors">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="color-preview p-3 rounded shadow-sm mb-2"
|
||||||
|
data-color-type="base"
|
||||||
|
style="background-color: var(--secondary-color); width: 80px; height: 80px;">
|
||||||
|
</div>
|
||||||
|
<small class="d-block text-muted">Base</small>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="color-preview p-3 rounded shadow-sm mb-2"
|
||||||
|
data-color-type="light"
|
||||||
|
style="background-color: var(--secondary-light); width: 80px; height: 80px;">
|
||||||
|
</div>
|
||||||
|
<small class="d-block text-muted">Light</small>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="color-preview p-3 rounded shadow-sm mb-2"
|
||||||
|
data-color-type="opacity"
|
||||||
|
style="background-color: var(--secondary-opacity-15); width: 80px; height: 80px;">
|
||||||
|
</div>
|
||||||
|
<small class="d-block text-muted">Opacity 15%</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-end gap-2">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#resetColorsModal">
|
||||||
|
<i class="fas fa-undo me-1"></i> Reset to Defaults
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="fas fa-save me-1"></i> Save Colors
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Reset Colors Confirmation Modal -->
|
||||||
|
<div id="resetColorsModal" class="modal fade" tabindex="-1" aria-labelledby="resetColorsModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="resetColorsModalLabel">Reset Colors</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
|
<i class="fas fa-exclamation-triangle text-warning" style="font-size: 2rem;"></i>
|
||||||
|
<div>
|
||||||
|
<h6 class="mb-1">Are you sure you want to reset the colors?</h6>
|
||||||
|
<p class="text-muted mb-0">This will restore the default theme colors.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<i class="fas fa-info-circle me-2"></i>
|
||||||
|
The primary color will be reset to #16767b and the secondary color to #741b5f.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<form method="POST" action="{{ url_for('main.reset_colors') }}" class="d-inline">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||||
|
<button type="submit" class="btn btn-warning">
|
||||||
|
<i class="fas fa-undo me-1"></i> Reset Colors
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const primaryColorInput = document.getElementById('primaryColor');
|
||||||
|
const secondaryColorInput = document.getElementById('secondaryColor');
|
||||||
|
|
||||||
|
// Color manipulation functions
|
||||||
|
function hexToRgb(hex) {
|
||||||
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
|
return result ? {
|
||||||
|
r: parseInt(result[1], 16),
|
||||||
|
g: parseInt(result[2], 16),
|
||||||
|
b: parseInt(result[3], 16)
|
||||||
|
} : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rgbToHex(r, g, b) {
|
||||||
|
return '#' + [r, g, b].map(x => {
|
||||||
|
const hex = x.toString(16);
|
||||||
|
return hex.length === 1 ? '0' + hex : hex;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function lightenColor(color, amount) {
|
||||||
|
const rgb = hexToRgb(color);
|
||||||
|
if (!rgb) return color;
|
||||||
|
|
||||||
|
return rgbToHex(
|
||||||
|
Math.min(255, Math.round(rgb.r + (255 - rgb.r) * amount)),
|
||||||
|
Math.min(255, Math.round(rgb.g + (255 - rgb.g) * amount)),
|
||||||
|
Math.min(255, Math.round(rgb.b + (255 - rgb.b) * amount))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function darkenColor(color, amount) {
|
||||||
|
const rgb = hexToRgb(color);
|
||||||
|
if (!rgb) return color;
|
||||||
|
|
||||||
|
return rgbToHex(
|
||||||
|
Math.max(0, Math.round(rgb.r * (1 - amount))),
|
||||||
|
Math.max(0, Math.round(rgb.g * (1 - amount))),
|
||||||
|
Math.max(0, Math.round(rgb.b * (1 - amount)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAllColors(color, isPrimary) {
|
||||||
|
const prefix = isPrimary ? 'primary' : 'secondary';
|
||||||
|
|
||||||
|
// Calculate derived colors
|
||||||
|
const lightColor = lightenColor(color, 0.15);
|
||||||
|
const bgLightColor = lightenColor(color, 0.9);
|
||||||
|
const opacity15 = color + '26'; // 15% opacity in hex
|
||||||
|
|
||||||
|
// Calculate chart colors
|
||||||
|
const chartColors = {
|
||||||
|
base: color,
|
||||||
|
light: lightenColor(color, 0.2),
|
||||||
|
lighter: lightenColor(color, 0.4),
|
||||||
|
lightest: lightenColor(color, 0.6),
|
||||||
|
pale: lightenColor(color, 0.8)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update CSS variables for the entire website
|
||||||
|
document.documentElement.style.setProperty(`--${prefix}-color`, color);
|
||||||
|
document.documentElement.style.setProperty(`--${prefix}-light`, lightColor);
|
||||||
|
document.documentElement.style.setProperty(`--${prefix}-bg-light`, bgLightColor);
|
||||||
|
document.documentElement.style.setProperty(`--${prefix}-opacity-15`, opacity15);
|
||||||
|
|
||||||
|
// Update chart color variables
|
||||||
|
document.documentElement.style.setProperty(`--chart-${prefix}`, chartColors.base);
|
||||||
|
document.documentElement.style.setProperty(`--chart-${prefix}-light`, chartColors.light);
|
||||||
|
document.documentElement.style.setProperty(`--chart-${prefix}-lighter`, chartColors.lighter);
|
||||||
|
document.documentElement.style.setProperty(`--chart-${prefix}-lightest`, chartColors.lightest);
|
||||||
|
document.documentElement.style.setProperty(`--chart-${prefix}-pale`, chartColors.pale);
|
||||||
|
|
||||||
|
// Update derived colors in the preview section
|
||||||
|
const derivedColorsSection = document.getElementById(`${prefix}DerivedColors`);
|
||||||
|
if (derivedColorsSection) {
|
||||||
|
const previews = derivedColorsSection.querySelectorAll('.color-preview');
|
||||||
|
previews.forEach(preview => {
|
||||||
|
const colorType = preview.getAttribute('data-color-type');
|
||||||
|
switch (colorType) {
|
||||||
|
case 'base':
|
||||||
|
preview.style.backgroundColor = color;
|
||||||
|
break;
|
||||||
|
case 'light':
|
||||||
|
preview.style.backgroundColor = lightColor;
|
||||||
|
break;
|
||||||
|
case 'bg-light':
|
||||||
|
preview.style.backgroundColor = bgLightColor;
|
||||||
|
break;
|
||||||
|
case 'opacity':
|
||||||
|
preview.style.backgroundColor = opacity15;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the color input value
|
||||||
|
if (isPrimary) {
|
||||||
|
primaryColorInput.value = color;
|
||||||
|
} else {
|
||||||
|
secondaryColorInput.value = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event listeners for color inputs
|
||||||
|
primaryColorInput.addEventListener('input', () => {
|
||||||
|
updateAllColors(primaryColorInput.value, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
secondaryColorInput.addEventListener('input', () => {
|
||||||
|
updateAllColors(secondaryColorInput.value, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize colors from database values
|
||||||
|
function initializeColors() {
|
||||||
|
// Reset inputs to original database values
|
||||||
|
primaryColorInput.value = primaryColorInput.dataset.originalValue;
|
||||||
|
secondaryColorInput.value = secondaryColorInput.dataset.originalValue;
|
||||||
|
|
||||||
|
// Update all color previews
|
||||||
|
updateAllColors(primaryColorInput.value, true);
|
||||||
|
updateAllColors(secondaryColorInput.value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize colors when the page loads
|
||||||
|
initializeColors();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/trash.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/trash.css') }}">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('main.dynamic_colors') }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
Reference in New Issue
Block a user