modern designe

This commit is contained in:
lelo 2026-01-17 19:41:50 +00:00
parent 643f9b3908
commit e2ce075c96
8 changed files with 476 additions and 235 deletions

View File

@ -1,44 +1,59 @@
/* Ensure html and body take full height */ /* Ensure html and body take full height */
html, body { html, body {
background-color: var(--light-background); background: var(--light-background);
color: var(--main-text-color); color: var(--main-text-color);
height: 100%; height: 100%;
margin: 0; margin: 0;
/* padding: 0; */
} }
/* Global Styles */ /* Global Styles */
body { body {
font-family: 'Helvetica Neue', Arial, sans-serif; font-family: 'Manrope', 'Segoe UI', sans-serif;
padding-top: 70px; /* Adjust to your header height */ padding-top: 0;
overflow-x: hidden; /* Prevent horizontal scroll */ overflow-x: hidden;
letter-spacing: 0.01em;
line-height: 1.6;
background:
radial-gradient(1200px 900px at -10% 10%, rgba(34, 211, 238, 0.12), transparent 40%),
radial-gradient(1100px 800px at 110% -20%, rgba(59, 130, 246, 0.14), transparent 45%),
var(--light-background);
} }
/* Header styles */
.site-header { /* Header styles */
background-color: var(--dark-background); .site-header {
background: linear-gradient(120deg, var(--dark-background), #13253f);
color: var(--header-text-color); color: var(--header-text-color);
position: fixed; position: sticky;
top: 0; top: 0;
width: 100%; width: 100%;
z-index: 1000; z-index: 2000;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 16px;
padding: 10px 20px; padding: 10px 20px;
}
.site-header img.logo { border-bottom: 1px solid rgba(255, 255, 255, 0.05);
height: 50px; }
margin-right: 15px;
} .site-header img.logo {
.site-header h1 { height: 54px;
font-size: 1.5em; margin-right: 6px;
filter: drop-shadow(0 8px 10px rgba(0, 0, 0, 0.25));
}
.site-header h1 {
font-size: 1.4rem;
margin: 0; margin: 0;
} letter-spacing: 0.08em;
text-transform: uppercase;
font-weight: 800;
}
.wrapper { .wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100%; min-height: 100%;
padding-bottom: 200px; padding-bottom: 220px;
} }
.wrapper > .admin-nav, .wrapper > .admin-nav,
@ -49,79 +64,159 @@ body {
.wrapper > main, .wrapper > main,
.wrapper > section { .wrapper > section {
flex: 1 1 auto; flex: 1 1 auto;
padding-top: 6px;
} }
.wrapper > footer { .wrapper > footer {
flex: 0 0 auto; flex: 0 0 auto;
} }
.container { .container {
max-width: 1200px; max-width: 1200px;
width: 90%; width: 95%;
margin: 0 auto;
padding: 20px 0;
} }
.container a { .container a {
font-size: 18px; font-size: 17px;
} }
.container-fluid { .container-fluid {
padding: 24px;
}
/* Carded content shell */
main.tab-content,
section.tab-content {
background: rgba(255, 255, 255, 0.92);
border: 1px solid var(--border-color);
box-shadow: none;
padding: 20px; padding: 20px;
margin-top: -1px;
}
/* Search view container (custom element) */
search {
display: block;
background: rgba(255, 255, 255, 0.92);
border: 1px solid var(--border-color);
border-radius: 0 0 16px 16px;
box-shadow: none;
margin-top: -1px;
padding: 16px 0 10px;
} }
/* Breadcrumb Styles */ /* Breadcrumb Styles */
.breadcrumb a { .breadcrumb {
font-size: 19px; display: flex;
text-decoration: none; align-items: center;
color: var(--main-text-color); gap: 8px;
flex-wrap: wrap;
padding: 10px 16px;
margin: 0 0 14px;
} }
.breadcrumb a {
font-size: 17px;
text-decoration: none;
color: var(--brand-navy);
font-weight: 700;
}
.breadcrumb span { .breadcrumb span {
font-size: 19px; font-size: 17px;
color: #ccc; color: var(--muted-text);
margin-left: 5px; margin: 0;
margin-right: 5px;
margin-bottom: 10px;
} }
/* Admin Nav Styles */ /* Admin Nav Styles */
.admin-nav { .admin-nav {
color: #ccc; color: var(--brand-ink);
border: 1px solid #ccc; border: 1px solid var(--border-color);
padding: 10px; background: rgba(255, 255, 255, 0.9);
background-color: #979797; margin-bottom: 12px;
width: 100vw;
margin-left: calc(50% - 50vw);
margin-right: calc(50% - 50vw);
box-sizing: border-box;
position: relative;
z-index: 1000;
overflow: visible;
}
.admin-nav-rail {
position: relative;
overflow: visible;
}
.admin-nav-track {
display: flex;
align-items: center;
flex-wrap: nowrap;
justify-content: flex-start;
overflow-x: auto;
overflow-y: visible;
-webkit-overflow-scrolling: touch;
white-space: nowrap;
} }
.admin-nav a { .admin-nav a {
color: #ccc; color: var(--brand-ink);
text-decoration: none; text-decoration: none;
padding: 5px 0; padding: 8px 12px;
font-weight: 600;
font-size: 13px;
border: 1px solid transparent;
background: linear-gradient(135deg, #fff, #f4f7fb);
transition: all 0.2s ease;
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.05);
flex-shrink: 0;
}
.admin-nav a:hover {
color: var(--brand-sky);
border-color: var(--border-color);
transform: translateY(-1px);
}
.admin-nav span {
color: var(--border-color);
display: none;
} }
.admin-nav .dropdown-toggle { .admin-nav .dropdown-toggle {
color: #ccc; color: var(--brand-ink);
text-decoration: none; padding: 8px 12px;
padding: 5px 0;
} }
.admin-nav .dropdown-toggle::after { .admin-nav .dropdown-toggle::after {
border-top-color: #ccc; display: none; /* hide default Bootstrap caret */
} }
.admin-nav .dropdown-menu { .admin-nav .dropdown-menu {
background-color: #f2f2f2; background-color: #fff;
border-color: #ccc; border-color: var(--border-color);
border-radius: 10px;
box-shadow: var(--card-shadow);
z-index: 4000;
position: absolute;
top: 0;
left: 100%;
margin-top: 0;
margin-left: 8px;
transform: none;
} }
.admin-nav .dropdown-item { .admin-nav .dropdown-item {
color: #333; color: var(--brand-ink);
padding-left: 14px; padding-left: 14px;
padding-right: 14px; padding-right: 14px;
} }
.admin-nav .dropdown-item:hover, .admin-nav .dropdown-item:hover,
.admin-nav .dropdown-item:focus { .admin-nav .dropdown-item:focus {
background-color: #e6e6e6; background-color: #eef4ff;
color: #000; color: var(--brand-navy);
} }
/* List Styles */ /* List Styles */
@ -138,18 +233,29 @@ div.directory-item a, li.directory-item a, li.file-item a, li.link-item a {
/* Directory Items (in a list) */ /* Directory Items (in a list) */
.directory-item, .link-item, .directory-item, .file-item { .directory-item, .link-item, .directory-item, .file-item {
margin-bottom: 10px; margin-bottom: 12px;
background-color: #fff; background-color: #fff;
border-radius: 5px; border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1); box-shadow: var(--card-shadow);
padding: 10px 15px; padding: 12px 18px;
border: 1px solid var(--border-color);
transition: all 0.2s ease;
}
.directory-item:hover,
.link-item:hover,
.file-item:hover {
border-color: var(--brand-sky);
box-shadow: 0 14px 26px rgba(59, 130, 246, 0.14);
transform: translateY(-1px);
} }
/* Grid Layout for Directories */ /* Grid Layout for Directories */
.directories-grid { .directories-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 0 10px; column-gap: 14px;
row-gap: 0;
text-align: center; text-align: center;
} }
@ -159,49 +265,58 @@ div.directory-item a, li.directory-item a, li.file-item a, li.link-item a {
grid-template-columns: 1fr auto; grid-template-columns: 1fr auto;
align-items: center; align-items: center;
background-color: #fff; background-color: #fff;
border-radius: 5px; border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1); box-shadow: var(--card-shadow);
} }
/* Link Styles */ /* Link Styles */
.directory-link, .directory-link,
.link-link, .link-link,
a.play-file { a.play-file {
color: var(--player-text-color); color: var(--brand-ink);
text-decoration: none; text-decoration: none;
word-break: break-all; word-break: break-all;
font-weight: 600;
} }
a.show-transcript { a.show-transcript {
text-decoration: none; text-decoration: none;
color: var(--main-text-color); color: var(--brand-navy);
font-size: 20px; font-size: 18px;
margin-left: 10px; margin-left: 10px;
font-weight: 600;
} }
a.show-transcript:hover { a.show-transcript:hover {
color: rgb(113, 146, 167); color: var(--brand-sky);
} }
.highlight { .highlight {
background-color: yellow; background-color: #fffbcc;
padding: 2px 4px;
border-radius: 4px;
} }
#transcriptContent code.timecode-link { #transcriptContent code.timecode-link {
cursor: pointer; cursor: pointer;
font-size: small; font-size: small;
} }
a.create-share { a.create-share {
text-decoration: none; text-decoration: none;
color: var(--main-text-color); color: var(--brand-navy);
font-size: 20px; font-size: 18px;
margin-left: 10px; margin-left: 10px;
font-weight: 600;
} }
a.create-share:hover { a.create-share:hover {
color: rgb(113, 146, 167); color: var(--brand-sky);
} }
.currently-playing { .currently-playing {
background-color: var(--selected-background); background-color: var(--selected-background);
border: 1px solid var(--brand-sky);
} }
/* Footer Player Styles */ /* Footer Player Styles */
@ -210,14 +325,15 @@ footer {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
background-color: var(--dark-background); background: linear-gradient(120deg, #0b1220, #0f172a);
color: #fff; color: #fff;
padding: 7px; padding: 10px 14px;
text-align: center; text-align: center;
z-index: 1000; /* Make sure it sits on top */ z-index: 1000; /* Make sure it sits on top */
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.25);
} }
/* Modal Styles */ /* Modal Styles */
@ -242,14 +358,18 @@ footer {
position: relative; position: relative;
max-height: 80vh; max-height: 80vh;
overflow-y: auto; overflow-y: auto;
display: flex;
flex-direction: column;
} }
#transcriptModal .close { #transcriptModal .close {
position: absolute; position: sticky;
right: 15px; top: 0;
top: 10px; right: 0;
font-size: 28px; font-size: 28px;
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
margin-left: auto;
z-index: 5;
} }
/* Basic Markdown Styles */ /* Basic Markdown Styles */
@ -313,9 +433,10 @@ footer {
.image-item { .image-item {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
border: 2px solid #ccc; border: 1px solid var(--border-color);
border-radius: 8px; border-radius: 12px;
background: #f9f9f9; background: linear-gradient(145deg, #ffffff, #f6f8fc);
box-shadow: var(--card-shadow);
} }
/* the filename overlay, centered at bottom */ /* the filename overlay, centered at bottom */
@ -422,41 +543,60 @@ footer {
/* Tab Navigation Styles */ /* Tab Navigation Styles */
.main-tabs { .main-tabs {
background-color: var(--dark-background);
display: flex; display: flex;
justify-content: center; justify-content: flex-start;
padding: 0; padding: 6px 18px 0;
margin: 0; gap: 0;
gap: 2px; border-bottom: 1px solid var(--border-color);
border-bottom: 2px solid #444; flex-wrap: nowrap;
border-radius: 0;
width: 100vw;
margin-left: calc(50% - 50vw);
margin-right: calc(50% - 50vw);
box-sizing: border-box;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: thin;
} }
.tab-button { .tab-button {
background: #333; background: rgba(217, 217, 217, 0.5);
border: 1px solid #444; border: 1px solid var(--border-color);
border-bottom: none; border-bottom: none;
color: #999; color: var(--muted-text);
padding: 6px 20px; padding: 10px 16px;
font-size: 14px; font-size: 13px;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
border-radius: 5px 5px 0 0; border-radius: 10px 10px 0 0;
margin: 0; margin: 0 6px 0 0;
position: relative; position: relative;
top: 2px; font-weight: 700;
letter-spacing: 0.04em;
text-transform: none;
box-shadow:
0 -10px 18px -12px rgba(15, 23, 42, 0.18),
10px 0 18px -12px rgba(15, 23, 42, 0.12),
-10px 0 18px -12px rgba(15, 23, 42, 0.12);
flex: 0 0 auto;
} }
.tab-button:hover { .tab-button:hover {
color: #fff; color: var(--brand-ink);
background: #3a3a3a; background: rgba(255, 255, 255, 0.92);
} }
.tab-button.active { .tab-button.active {
color: var(--main-text-color, #000); color: var(--brand-ink);
background: var(--light-background); background: rgba(255, 255, 255, 0.92);
border-color: #444; border-color: var(--border-color);
border-bottom-color: var(--light-background); z-index: 2;
z-index: 1; box-shadow:
0 -12px 22px -12px rgba(15, 23, 42, 0.22),
12px 0 20px -14px rgba(15, 23, 42, 0.14),
-12px 0 20px -14px rgba(15, 23, 42, 0.14);
margin-bottom: -1px;
} }
.tab-content { .tab-content {
@ -471,27 +611,28 @@ footer {
.messages-section-header { .messages-section-header {
max-width: 900px; max-width: 900px;
margin: 0 auto; margin: 0 auto;
padding: 0 0 8px; padding: 0 0 10px;
} }
.messages-container { .messages-container {
max-width: 900px; max-width: 900px;
margin: 0 auto; margin: 0 auto;
padding: 20px 0; padding: 10px 0 24px;
} }
.message-card { .message-card {
background: var(--card-background, #fff); background: linear-gradient(145deg, #ffffff, #f7f9ff);
border: 1px solid #ddd; border: 1px solid var(--border-color);
border-radius: 8px; border-radius: 14px;
padding: 20px; padding: 20px 22px;
margin-bottom: 20px; margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1); box-shadow: var(--card-shadow);
transition: box-shadow 0.3s ease; transition: box-shadow 0.3s ease, transform 0.2s ease;
} }
.message-card:hover { .message-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.15); box-shadow: 0 20px 38px rgba(15, 23, 42, 0.16);
transform: translateY(-2px);
} }
.message-header { .message-header {
@ -500,18 +641,18 @@ footer {
align-items: center; align-items: center;
margin-bottom: 15px; margin-bottom: 15px;
padding-bottom: 10px; padding-bottom: 10px;
border-bottom: 2px solid #e0e0e0; border-bottom: 1px dashed var(--border-color);
} }
.message-title { .message-title {
font-size: 1.5em; font-size: 1.5em;
font-weight: bold; font-weight: bold;
color: var(--main-text-color); color: var(--brand-ink);
margin: 0; margin: 0;
} }
.message-datetime { .message-datetime {
color: #666; color: var(--muted-text);
font-size: 0.9em; font-size: 0.9em;
font-style: italic; font-style: italic;
} }
@ -527,9 +668,9 @@ footer {
gap: 6px; gap: 6px;
padding: 8px 16px; padding: 8px 16px;
margin: 4px 0; margin: 4px 0;
background: #f0f4f8; background: #ecf6ff;
color: #495057; color: #0f172a;
border: 1px solid #d1dce5; border: 1px solid #bed8ff;
border-radius: 6px; border-radius: 6px;
font-size: 0.95em; font-size: 0.95em;
font-weight: 500; font-weight: 500;
@ -539,9 +680,9 @@ footer {
} }
.message-content .folder-link-btn:hover { .message-content .folder-link-btn:hover {
background: #e3eaf0; background: #dff0ff;
border-color: #b8c5d0; border-color: #93c5fd;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.12); box-shadow: 0 6px 18px rgba(14, 165, 233, 0.24);
} }
.message-content .folder-link-btn:active { .message-content .folder-link-btn:active {
@ -554,13 +695,13 @@ footer {
} }
.message-content a { .message-content a {
color: #007bff; color: var(--brand-sky);
text-decoration: underline; text-decoration: underline;
cursor: pointer; cursor: pointer;
} }
.message-content a:hover { .message-content a:hover {
color: #0056b3; color: #0ea5e9;
text-decoration: underline; text-decoration: underline;
} }
@ -620,10 +761,12 @@ footer {
} }
.message-content blockquote { .message-content blockquote {
border-left: 4px solid #ccc; border-left: 4px solid var(--border-color);
padding-left: 15px; padding-left: 15px;
color: #666; color: var(--muted-text);
font-style: italic; font-style: italic;
background: #f8fbff;
border-radius: 6px;
} }
.message-image { .message-image {
@ -638,7 +781,7 @@ footer {
.message-actions { .message-actions {
margin-top: 15px; margin-top: 15px;
padding-top: 10px; padding-top: 10px;
border-top: 1px solid #e0e0e0; border-top: 1px solid var(--border-color);
display: flex; display: flex;
gap: 10px; gap: 10px;
} }
@ -654,12 +797,12 @@ footer {
} }
.btn-edit { .btn-edit {
background-color: #007bff; background: linear-gradient(135deg, #2563eb, #22d3ee);
color: white; color: white;
} }
.btn-edit:hover { .btn-edit:hover {
background-color: #0056b3; background: linear-gradient(135deg, #1d4ed8, #0ea5e9);
} }
.btn-delete { .btn-delete {
@ -674,7 +817,7 @@ footer {
.no-messages { .no-messages {
text-align: center; text-align: center;
padding: 40px; padding: 40px;
color: #999; color: var(--muted-text);
font-size: 1.2em; font-size: 1.2em;
} }
@ -690,9 +833,9 @@ footer {
display: grid; display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr)); grid-template-columns: repeat(1, minmax(0, 1fr));
gap: 0; gap: 0;
border: 1px solid #ddd; border: 1px solid var(--border-color);
border-top: 0; border-top: 0;
border-radius: 0 0 6px 6px; border-radius: 0 0 10px 10px;
overflow: visible; overflow: visible;
} }
@ -701,9 +844,9 @@ footer {
} }
.calendar-day { .calendar-day {
background: var(--card-background, #fff); background: #ffffff;
border-bottom: 1px solid #ddd; border-bottom: 1px solid var(--border-color);
padding: 8px 10px 4px; padding: 12px 12px 6px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-width: 0; min-width: 0;
@ -713,19 +856,19 @@ footer {
} }
.calendar-day-today { .calendar-day-today {
background: #f7fbff; background: linear-gradient(135deg, #f6fbff, #ecf4ff);
box-shadow: inset 0 0 0 2px #4da3ff; box-shadow: inset 0 0 0 2px #3b82f6;
border-color: #4da3ff; border-color: #3b82f6;
} }
.calendar-day-sunday, .calendar-day-sunday,
.calendar-day-holiday { .calendar-day-holiday {
background: #fff7f7; background: #fff8f5;
} }
.calendar-day-today.calendar-day-sunday, .calendar-day-today.calendar-day-sunday,
.calendar-day-today.calendar-day-holiday { .calendar-day-today.calendar-day-holiday {
background: linear-gradient(135deg, #f7fbff 0%, #f7fbff 60%, #fff2f2 100%); background: linear-gradient(135deg, #f6fbff 0%, #f6fbff 60%, #fff1ed 100%);
} }
.calendar-day-sunday .calendar-day-header, .calendar-day-sunday .calendar-day-header,
@ -757,7 +900,7 @@ footer {
@media (min-width: 992px) { @media (min-width: 992px) {
.calendar-grid { .calendar-grid {
grid-template-columns: repeat(7, minmax(0, 1fr)); grid-template-columns: repeat(7, minmax(0, 1fr));
border-radius: 0 0 8px 8px; border-radius: 0 0 12px 12px;
} }
.calendar-weekday-header { .calendar-weekday-header {
@ -765,21 +908,21 @@ footer {
grid-template-columns: repeat(7, minmax(0, 1fr)); grid-template-columns: repeat(7, minmax(0, 1fr));
text-align: center; text-align: center;
font-weight: 600; font-weight: 600;
color: #999; color: var(--muted-text);
border: 1px solid #ddd; border: 1px solid var(--border-color);
border-bottom: 0; border-bottom: 0;
border-radius: 8px 8px 0 0; border-radius: 12px 12px 0 0;
overflow: visible; overflow: visible;
position: sticky; position: sticky;
top: 70px; top: 70px;
z-index: 900; z-index: 900;
background: var(--card-background, #fff); background: var(--card-background, #fff);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04); box-shadow: 0 10px 28px rgba(0, 0, 0, 0.05);
} }
.calendar-day { .calendar-day {
border-bottom: 1px solid #ddd; border-bottom: 1px solid var(--border-color);
border-right: 1px solid #ddd; border-right: 1px solid var(--border-color);
} }
.calendar-day:nth-child(7n) { .calendar-day:nth-child(7n) {
@ -795,17 +938,17 @@ footer {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 6px; margin-bottom: 8px;
gap: 8px; gap: 8px;
} }
.calendar-day-name { .calendar-day-name {
font-weight: 600; font-weight: 700;
text-transform: capitalize; text-transform: capitalize;
} }
.calendar-day-date { .calendar-day-date {
color: #666; color: var(--muted-text);
font-size: 0.95rem; font-size: 0.95rem;
white-space: nowrap; white-space: nowrap;
} }
@ -817,9 +960,9 @@ footer {
} }
.calendar-day thead th { .calendar-day thead th {
background: #f1f1f1; background: #f6f8fb;
color: #666; color: var(--muted-text);
border-color: #ddd; border-color: var(--border-color);
} }
.calendar-day.empty thead { .calendar-day.empty thead {
@ -851,7 +994,7 @@ footer {
.details-indicator { .details-indicator {
font-weight: 700; font-weight: 700;
color: #666; color: var(--brand-sky);
margin-left: 6px; margin-left: 6px;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
@ -869,7 +1012,7 @@ footer {
} }
.calendar-details-row td { .calendar-details-row td {
background: #f8f9fa; background: #f8fbff;
} }
.calendar-inline-actions { .calendar-inline-actions {
@ -882,8 +1025,10 @@ footer {
.file-browser-content { .file-browser-content {
max-height: 400px; max-height: 400px;
overflow-y: auto; overflow-y: auto;
border: 1px solid #ddd; border: 1px solid var(--border-color);
border-radius: 5px; border-radius: 10px;
background: #fff;
box-shadow: var(--card-shadow);
} }
.file-browser-content .list-group-item { .file-browser-content .list-group-item {
@ -906,15 +1051,15 @@ footer {
} }
.file-browser-panel { .file-browser-panel {
background-color: #f5f5f5; background-color: #f8fbff;
border: 1px solid #ddd; border: 1px solid var(--border-color);
border-radius: 5px; border-radius: 12px;
padding: 15px; padding: 16px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.file-browser-panel h6 { .file-browser-panel h6 {
margin-top: 0; margin-top: 0;
margin-bottom: 10px; margin-bottom: 10px;
color: #333; color: var(--brand-ink);
} }

View File

@ -252,9 +252,9 @@ function renderContent(data) {
contentHTML += '<div class="directories-grid">'; contentHTML += '<div class="directories-grid">';
data.directories.forEach(dir => { data.directories.forEach(dir => {
if (admin_enabled && data.breadcrumbs.length != 1 && dir.share) { if (admin_enabled && data.breadcrumbs.length != 1 && dir.share) {
share_link = `<a href="#" class="create-share" data-url="${dir.path}">⚙️</a>`; share_link = `<a href="#" class="create-share" data-url="${dir.path}"><i class="bi bi-gear"></i></a>`;
} }
contentHTML += `<div class="directory-item"><a href="#" class="directory-link" data-path="${dir.path}">📁 ${dir.name}</a> contentHTML += `<div class="directory-item"><a href="#" class="directory-link" data-path="${dir.path}"><i class="bi bi-folder"></i> ${dir.name}</a>
${share_link} ${share_link}
</div>`; </div>`;
}); });
@ -262,22 +262,22 @@ function renderContent(data) {
} else { } else {
contentHTML += '<ul>'; contentHTML += '<ul>';
if (data.breadcrumbs.length === 1 && Array.isArray(data.folder_today) && data.folder_today.length > 0) { if (data.breadcrumbs.length === 1 && Array.isArray(data.folder_today) && data.folder_today.length > 0) {
contentHTML += `<li class="directory-item"><a href="#" class="directory-link" data-path="heute">📅 Heute</a></li>`; contentHTML += `<li class="directory-item"><a href="#" class="directory-link" data-path="heute"><i class="bi bi-calendar2-day"></i> Heute</a></li>`;
} else if (data.breadcrumbs.length === 1 && Array.isArray(data.folder_yesterday) && data.folder_yesterday.length > 0) { } else if (data.breadcrumbs.length === 1 && Array.isArray(data.folder_yesterday) && data.folder_yesterday.length > 0) {
contentHTML += `<li class="directory-item"><a href="#" class="directory-link" data-path="gestern">📅 Gestern</a></li>`; contentHTML += `<li class="directory-item"><a href="#" class="directory-link" data-path="gestern"><i class="bi bi-calendar2-day"></i> Gestern</a></li>`;
} }
if (data.breadcrumbs.length === 1 && data.toplist_enabled) { if (data.breadcrumbs.length === 1 && data.toplist_enabled) {
contentHTML += `<li class="directory-item"><a href="#" class="directory-link" data-path="toplist">🔥 oft angehört</a></li>`; contentHTML += `<li class="directory-item"><a href="#" class="directory-link" data-path="toplist"><i class="bi bi-graph-up"></i> oft angehört</a></li>`;
} }
data.directories.forEach(dir => { data.directories.forEach(dir => {
if (admin_enabled && data.breadcrumbs.length != 1 && dir.share) { if (admin_enabled && data.breadcrumbs.length != 1 && dir.share) {
share_link = `<a href="#" class="create-share" data-url="${dir.path}">⚙️</a>`; share_link = `<a href="#" class="create-share" data-url="${dir.path}"><i class="bi bi-gear"></i></a>`;
} }
if (dir.path.includes('toplist')) { if (dir.path.includes('toplist')) {
link_symbol = ''; link_symbol = '<i class="bi bi-star"></i>';
} else { } else {
link_symbol = '📁'; link_symbol = '<i class="bi bi-folder"></i>';
} }
contentHTML += `<li class="directory-item"><a href="#" class="directory-link" data-path="${dir.path}">${link_symbol} ${dir.name}</a>${share_link}</li>`; contentHTML += `<li class="directory-item"><a href="#" class="directory-link" data-path="${dir.path}">${link_symbol} ${dir.name}</a>${share_link}</li>`;
}); });
@ -286,7 +286,7 @@ function renderContent(data) {
} }
// Add search link at top level above directories/files // Add search link at top level above directories/files
if (data.breadcrumbs.length === 1) { if (data.breadcrumbs.length === 1) {
contentHTML = `<ul><li class="link-item" onclick="viewSearch()"><a onclick="viewSearch()" class="link-link">🔎 Suche</a></li></ul>` + contentHTML; contentHTML = `<ul><li class="link-item" onclick="viewSearch()"><a onclick="viewSearch()" class="link-link"><i class="bi bi-search"></i> Suche</a></li></ul>` + contentHTML;
} }
// Render files (including music and non-image files) // Render files (including music and non-image files)
@ -294,18 +294,18 @@ function renderContent(data) {
if (nonImageFiles.length > 0) { if (nonImageFiles.length > 0) {
contentHTML += '<ul>'; contentHTML += '<ul>';
nonImageFiles.forEach((file, idx) => { nonImageFiles.forEach((file, idx) => {
let symbol = '📄'; let symbol = '<i class="bi bi-file-earmark"></i>';
if (file.file_type === 'music') { if (file.file_type === 'music') {
symbol = '🔊'; symbol = '<i class="bi bi-volume-up"></i>';
currentMusicFiles.push({ path: file.path, index: idx, title: file.name.replace('.mp3', '') }); currentMusicFiles.push({ path: file.path, index: idx, title: file.name.replace('.mp3', '') });
} else if (file.file_type === 'image') { } else if (file.file_type === 'image') {
symbol = '🖼️'; symbol = '<i class="bi bi-image"></i>';
} }
const indexAttr = file.file_type === 'music' ? ` data-index="${currentMusicFiles.length - 1}"` : ''; const indexAttr = file.file_type === 'music' ? ` data-index="${currentMusicFiles.length - 1}"` : '';
contentHTML += `<li class="file-item"> contentHTML += `<li class="file-item">
<a href="#" class="play-file"${indexAttr} data-url="${file.path}" data-file-type="${file.file_type}">${symbol} ${file.name.replace('.mp3', '')}</a>`; <a href="#" class="play-file"${indexAttr} data-url="${file.path}" data-file-type="${file.file_type}">${symbol} ${file.name.replace('.mp3', '')}</a>`;
if (file.has_transcript) { if (file.has_transcript) {
contentHTML += `<a href="#" class="show-transcript" data-url="${file.transcript_url}" data-audio-url="${file.path}" title="Show Transcript">&#128196;</a>`; contentHTML += `<a href="#" class="show-transcript" data-url="${file.transcript_url}" data-audio-url="${file.path}" title="Show Transcript"><i class="bi bi-journal-text"></i></a>`;
} }
contentHTML += `</li>`; contentHTML += `</li>`;
}); });

View File

@ -1,23 +1,24 @@
.audio-player-container { .audio-player-container {
background-color: #fff; background: linear-gradient(135deg, #f9fbff, #eef4ff);
border-radius: 8px; border-radius: 14px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); box-shadow: 0 12px 26px rgba(15, 23, 42, 0.12);
padding: 7px; border: 1px solid #d7e3f4;
width: 100%; padding: 12px 16px;
width: min(1100px, 100%);
display: none; display: none;
color: #1f2937;
} }
/* Now Playing Info */ /* Now Playing Info */
.now-playing-info { .now-playing-info {
margin-top: 5px; margin-top: 5px;
font-size: 16px; font-size: 15px;
color: var(--main-text-color); color: #1f2937;
text-align: center; text-align: center;
} }
.audio-player { .audio-player {
--player-button-width: 4em; --control-size: 3.4em;
--sound-button-width: 3em;
--space: 0.5em; --space: 0.5em;
} }
@ -26,6 +27,7 @@
align-items: center; align-items: center;
width: 100%; width: 100%;
gap: var(--space); /* ensures spacing between controls */ gap: var(--space); /* ensures spacing between controls */
color: #1f2937;
} }
/* Make the slider container fill the available space and stack its children vertically */ /* Make the slider container fill the available space and stack its children vertically */
@ -40,10 +42,10 @@
-webkit-appearance: none; -webkit-appearance: none;
width: 100%; width: 100%;
height: 0.5em; height: 0.5em;
background-color: #ccc; background-color: #e6edf7;
border-radius: 5px; border-radius: 5px;
background-size: 0% 100%; background-size: 0% 100%;
background-image: linear-gradient(var(--dark-background), var(--dark-background)); background-image: linear-gradient(90deg, #0b1220, #0f172a);
background-repeat: no-repeat; background-repeat: no-repeat;
appearance: none; appearance: none;
outline: none; outline: none;
@ -56,9 +58,9 @@
width: 1em; width: 1em;
height: 1em; height: 1em;
border-radius: 50%; border-radius: 50%;
background-color: var(--dark-background); background-color: #0f172a;
cursor: pointer; cursor: pointer;
border: none; border: 2px solid #0b1220;
outline: none; outline: none;
} }
@ -67,9 +69,9 @@
width: 1em; width: 1em;
height: 1em; height: 1em;
border-radius: 50%; border-radius: 50%;
background-color: var(--dark-background); background-color: #0f172a;
cursor: pointer; cursor: pointer;
border: none; border: 2px solid #0b1220;
outline: none; outline: none;
} }
@ -78,9 +80,9 @@
width: 1em; width: 1em;
height: 1em; height: 1em;
border-radius: 50%; border-radius: 50%;
background-color: var(--dark-background); background-color: #0f172a;
cursor: pointer; cursor: pointer;
border: none; border: 2px solid #0b1220;
outline: none; outline: none;
} }
@ -104,18 +106,37 @@
.player-button, .player-button,
.sound-button { .sound-button {
background-color: transparent; background-color: #0f172a;
border: 0; border: 1px solid #0f172a;
cursor: pointer; cursor: pointer;
padding: 0; padding: 6px;
border-radius: 12px;
transition: background-color 0.2s ease, transform 0.2s ease;
} }
.player-button { .player-button {
width: var(--player-button-width); width: var(--control-size);
height: var(--player-button-width); height: var(--control-size);
} }
.sound-button { .sound-button {
width: var(--sound-button-width); width: var(--control-size);
height: var(--sound-button-width); height: var(--control-size);
}
.player-button:hover,
.sound-button:hover {
background-color: #0b1220;
transform: translateY(-1px);
}
.player-button svg path,
.sound-button svg path {
fill: #f9fbff;
}
.timeline::-webkit-slider-thumb,
.timeline::-moz-range-thumb,
.timeline::-ms-thumb {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
} }

View File

@ -417,7 +417,7 @@ function setAutoPlay(active) {
const playButton = document.getElementById('gallery-play'); const playButton = document.getElementById('gallery-play');
isAutoPlay = active; isAutoPlay = active;
if (playButton) { if (playButton) {
playButton.textContent = active ? '⏸' : '▶'; playButton.textContent = active ? '||' : '>';
playButton.setAttribute('aria-pressed', active ? 'true' : 'false'); playButton.setAttribute('aria-pressed', active ? 'true' : 'false');
playButton.classList.toggle('playing', active); playButton.classList.toggle('playing', active);
} }

View File

@ -1,6 +1,66 @@
document.addEventListener('DOMContentLoaded', function() { function wireAdminDropdowns() {
// (No per-icon setup needed here—just ensure your CSS is in place.) const reposition = (toggle, menu) => {
const rect = toggle.getBoundingClientRect();
const gutter = 8;
const menuWidth = menu.offsetWidth || 220;
const menuHeight = menu.offsetHeight || 0;
// Prefer placing the menu to the right of the toggle; clamp within viewport.
let left = rect.right + gutter;
if (left + menuWidth > window.innerWidth - gutter) {
left = Math.max(gutter, window.innerWidth - menuWidth - gutter);
}
let top = Math.max(gutter, Math.min(rect.top, window.innerHeight - menuHeight - gutter));
menu.style.position = 'fixed';
menu.style.transform = 'none';
menu.style.top = `${top}px`;
menu.style.left = `${left}px`;
menu.style.right = 'auto';
menu.style.minWidth = `${Math.max(rect.width, 160)}px`;
menu.style.maxWidth = '260px';
menu.style.display = 'block';
menu.dataset.dropdownOpen = '1';
menu.classList.add('show');
};
const resetMenu = (menu) => {
menu.style.position = '';
menu.style.transform = '';
menu.style.top = '';
menu.style.left = '';
menu.style.right = '';
menu.style.minWidth = '';
menu.style.maxWidth = '';
menu.style.display = '';
menu.classList.remove('show');
delete menu.dataset.dropdownOpen;
};
document.querySelectorAll('.admin-nav .dropdown-toggle').forEach((toggle) => {
if (toggle.dataset.dropdownWired) return;
toggle.dataset.dropdownWired = '1';
const menu = toggle.nextElementSibling;
if (!menu) return;
toggle.addEventListener('shown.bs.dropdown', () => reposition(toggle, menu));
toggle.addEventListener('hide.bs.dropdown', () => resetMenu(menu));
window.addEventListener('scroll', () => {
if (menu.dataset.dropdownOpen) reposition(toggle, menu);
}, { passive: true });
window.addEventListener('resize', () => {
if (menu.dataset.dropdownOpen) reposition(toggle, menu);
}); });
});
}
if (document.readyState === 'complete' || document.readyState === 'interactive') {
wireAdminDropdowns();
} else {
document.addEventListener('DOMContentLoaded', wireAdminDropdowns);
}
// 1) Delegate clicks on any .toggle-icon, now or in the future: // 1) Delegate clicks on any .toggle-icon, now or in the future:
document.addEventListener('click', function(e) { document.addEventListener('click', function(e) {

View File

@ -14,11 +14,11 @@ document.addEventListener('DOMContentLoaded', function() {
card.className = 'card'; card.className = 'card';
card.innerHTML = ` card.innerHTML = `
<div class="card-body"> <div class="card-body">
<p><button class="btn btn-light" onclick="player.loadTrack('${file.relative_path}')" style="width:100%;">🔊 ${filenameWithoutExtension}</button></p> <p><button class="btn btn-light" onclick="player.loadTrack('${file.relative_path}')" style="width:100%;"><i class="bi bi-volume-up"></i> ${filenameWithoutExtension}</button></p>
<p><button onclick="window.open('/path/${file.relative_path}', '_self');" class="btn btn-light btn-sm" style="width:100%;">📁 ${parentFolder}</button></p> <p><button onclick="window.open('/path/${file.relative_path}', '_self');" class="btn btn-light btn-sm" style="width:100%;"><i class="bi bi-folder"></i> ${parentFolder}</button></p>
<p class="card-text">Anzahl Downloads: ${file.hitcount}</p> <p class="card-text">Anzahl Downloads: ${file.hitcount}</p>
${ file.performance_date !== undefined ? `<p class="card-text">Datum: ${file.performance_date}</p>` : ``} ${ file.performance_date !== undefined ? `<p class="card-text">Datum: ${file.performance_date}</p>` : ``}
${ file.transcript_hits !== undefined ? `<p class="card-text">Treffer im Transkript: ${file.transcript_hits} <a href="#" class="show-transcript" data-url="${transcriptURL}" data-audio-url="${file.relative_path}" highlight="${file.query}">&#128196;</a></p>` : ``} ${ file.transcript_hits !== undefined ? `<p class="card-text">Treffer im Transkript: ${file.transcript_hits} <a href="#" class="show-transcript" data-url="${transcriptURL}" data-audio-url="${file.relative_path}" highlight="${file.query}"><i class="bi bi-journal-text"></i></a></p>` : ``}
</div> </div>
`; `;
resultsDiv.appendChild(card); resultsDiv.appendChild(card);

View File

@ -29,6 +29,10 @@
<meta name="mobile-web-app-status-bar-style" content="default"> <meta name="mobile-web-app-status-bar-style" content="default">
<meta name="mobile-web-app-title" content="Gottesdienste"> <meta name="mobile-web-app-title" content="Gottesdienste">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">
@ -51,12 +55,14 @@
<div class="wrapper"> <div class="wrapper">
{% if admin_enabled %} {% if admin_enabled %}
<div class="admin-nav"> <div class="admin-nav">
<div class="admin-nav-rail">
<div class="admin-nav-track">
<a href="{{ url_for('mylinks') }}">Meine Links</a> <a href="{{ url_for('mylinks') }}">Meine Links</a>
<span> | </span> <span> | </span>
<a href="{{ url_for('folder_secret_config_editor') }}" id="edit-folder-config">Ordnerkonfiguration</a> <a href="{{ url_for('folder_secret_config_editor') }}" id="edit-folder-config">Ordnerkonfiguration</a>
<span> | </span> <span> | </span>
<div class="dropdown d-inline-block"> <div class="dropdown dropend d-inline-block">
<a class="dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"> <a class="dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false">
Auswertungen Auswertungen
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
@ -68,6 +74,8 @@
</ul> </ul>
</div> </div>
</div> </div>
</div>
</div>
{% endif %} {% endif %}
{% if features %} {% if features %}
@ -81,7 +89,6 @@
<!-- Browse Section --> <!-- Browse Section -->
<main id="browse-section" class="tab-content active"> <main id="browse-section" class="tab-content active">
<div class="container">
<div id="breadcrumbs" class="breadcrumb"></div> <div id="breadcrumbs" class="breadcrumb"></div>
<div id="content"></div> <div id="content"></div>
<div id="directory-controls"> <div id="directory-controls">
@ -93,7 +100,6 @@
</svg> </svg>
</button> </button>
</div> </div>
</div>
</main> </main>
{% include 'messages_section.html' %} {% include 'messages_section.html' %}
@ -257,7 +263,7 @@
<img id="gallery-modal-content" src="" /> <img id="gallery-modal-content" src="" />
<button class="gallery-nav gallery-prev"></button> <button class="gallery-nav gallery-prev"></button>
<button class="gallery-nav gallery-next"></button> <button class="gallery-nav gallery-next"></button>
<button id="gallery-play" aria-pressed="false"></button> <button id="gallery-play" aria-pressed="false" aria-label="Start slideshow">&gt;</button>
<div id="gallery-exif" aria-live="polite"></div> <div id="gallery-exif" aria-live="polite"></div>
<div id="gallery-filename" aria-live="polite"></div> <div id="gallery-filename" aria-live="polite"></div>
</div> </div>
@ -278,6 +284,7 @@
<script src="{{ url_for('static', filename='gallery.js') }}"></script> <script src="{{ url_for('static', filename='gallery.js') }}"></script>
<script src="{{ url_for('static', filename='search.js') }}"></script> <script src="{{ url_for('static', filename='search.js') }}"></script>
<script src="{{ url_for('static', filename='messages.js') }}"></script> <script src="{{ url_for('static', filename='messages.js') }}"></script>
<script src="{{ url_for('static', filename='general.js') }}"></script>
<script> <script>
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {
window.addEventListener('load', () => { window.addEventListener('load', () => {

View File

@ -10,6 +10,10 @@
<!-- Android Theme Color --> <!-- Android Theme Color -->
<meta name="theme-color" content="#000"> <meta name="theme-color" content="#000">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='theme.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='theme.css') }}">
@ -29,14 +33,16 @@
{% if admin_enabled %} {% if admin_enabled %}
<!-- Navigation Bar --> <!-- Navigation Bar -->
<div class="admin-nav"> <div class="admin-nav">
<div class="admin-nav-rail">
<div class="admin-nav-track">
<a href="{{ url_for('index') }}">App</a> <a href="{{ url_for('index') }}">App</a>
<span> | </span> <span> | </span>
<a href="{{ url_for('mylinks') }}">Meine Links</a> <a href="{{ url_for('mylinks') }}">Meine Links</a>
<span> | </span> <span> | </span>
<a href="{{ url_for('folder_secret_config_editor') }}" id="edit-folder-config">Ordnerkonfiguration</a> <a href="{{ url_for('folder_secret_config_editor') }}" id="edit-folder-config">Ordnerkonfiguration</a>
<span> | </span> <span> | </span>
<div class="dropdown d-inline-block"> <div class="dropdown dropend d-inline-block">
<a class="dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"> <a class="dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false">
Auswertungen Auswertungen
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
@ -48,13 +54,15 @@
</ul> </ul>
</div> </div>
</div> </div>
</div>
</div>
{% endif %} {% endif %}
{% block content %}{% endblock %} {% block content %}{% endblock %}
</div> </div>
{% block scripts %}{% endblock %} {% block scripts %}{% endblock %}
<script src="{{ url_for('static', filename='general.js') }}"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="{{ url_for('static', filename='general.js') }}"></script>
</body> </body>
</html> </html>