-
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
a {
|
||||
color: var(--primary-blue, #1e88e5);
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--primary-blue-dark, #1565c0);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.bg-success {
|
||||
background-color: #8BC34A!important;
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: var(--primary-blue, #1e88e5)!important;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: #D40000!important;
|
||||
}
|
||||
a.text-danger:focus,
|
||||
a.text-danger:hover {
|
||||
color: #790000!important;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
font-weight: var(--font-weight-medium, 550);
|
||||
font-size: var(--font-size-base, 0.945rem);
|
||||
padding: 12px 24px;
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--primary-blue, #0078D4);
|
||||
border: none;
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--primary-blue-dark, #005A9E);
|
||||
border: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--color-secondary, #64748B);
|
||||
border: none;
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: var(--color-secondary-dark, #475569);
|
||||
border: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-light {
|
||||
background-color: var(--bg-light, #f8f9fa);
|
||||
border: 2px solid var(--border-color, #e2e8f0);
|
||||
font-weight: var(--font-weight-medium, 550);
|
||||
}
|
||||
|
||||
.btn-light:hover {
|
||||
background-color: var(--bg-sidebar, #F1F5F9);
|
||||
border-color: var(--border-light, #cbd5e1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: var(--color-danger, #DC2626);
|
||||
border: none;
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: var(--color-danger-dark, #B91C1C);
|
||||
border: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: var(--color-success, #16A34A);
|
||||
border: none;
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
background: var(--color-success-dark, #15803D);
|
||||
border: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 8px 16px;
|
||||
font-size: var(--font-size-sm, 0.925rem);
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
padding: 16px 32px;
|
||||
font-size: var(--font-size-lg, 1.08rem);
|
||||
}
|
||||
|
||||
.btn-light.focus, .btn-light:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn.focus, .btn:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Form */
|
||||
.form-control {
|
||||
font-size: var(--font-size-base, 0.945rem);
|
||||
font-weight: var(--font-weight-normal, 450);
|
||||
padding: 12px 16px;
|
||||
border: 2px solid var(--border-color, #e2e8f0);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
color: var(--text-primary, #0F172A);
|
||||
margin-bottom: 8px;
|
||||
font-size: var(--font-size-base, 0.945rem);
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: var(--radius-md, 8px);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background: transparent;
|
||||
border-bottom: 1px solid var(--border-color, #e2e8f0);
|
||||
font-weight: var(--font-weight-bold, 750);
|
||||
font-size: var(--font-size-lg, 1.08rem);
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.table-striped tbody tr:nth-of-type(odd) {
|
||||
background-color: var(--bg-warm, #faf8f5);
|
||||
}
|
||||
|
||||
.table-striped tbody tr:hover {
|
||||
background-color: var(--bg-warm-card, #f7f5f2);
|
||||
}
|
||||
|
||||
.table thead th {
|
||||
font-size: var(--font-size-xs, 0.8rem);
|
||||
text-transform: uppercase!important;
|
||||
font-weight: var(--font-weight-bold, 750);
|
||||
color: var(--text-secondary, #475569);
|
||||
letter-spacing: 0.8px;
|
||||
border-bottom: 2px solid var(--border-color, #e2e8f0);
|
||||
}
|
||||
|
||||
.table td {
|
||||
font-size: var(--font-size-base, 0.945rem);
|
||||
font-weight: var(--font-weight-normal, 450);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: var(--text-primary, #0F172A);
|
||||
font-weight: var(--font-weight-bold, 750);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
h1 { font-size: var(--font-size-3xl, 2.25rem); }
|
||||
h2 { font-size: var(--font-size-2xl, 1.75rem); }
|
||||
h3 { font-size: var(--font-size-xl, 1.4rem); }
|
||||
h4 { font-size: var(--font-size-lg, 1.08rem); }
|
||||
h5 { font-size: var(--font-size-base, 0.945rem); }
|
||||
h6 { font-size: var(--font-size-sm, 0.925rem); }
|
||||
|
||||
/* Badge */
|
||||
.badge {
|
||||
font-size: var(--font-size-xs, 0.8rem);
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
padding: 6px 12px;
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
background: var(--primary-blue, #0078D4);
|
||||
}
|
||||
@@ -0,0 +1,800 @@
|
||||
:root {
|
||||
/* Dynamic font sizing */
|
||||
--font-size-xs: 0.72rem;
|
||||
--font-size-sm: 0.833rem;
|
||||
--font-size-base: 0.945rem;
|
||||
--font-size-lg: 1.08rem;
|
||||
--font-size-xl: 1.26rem;
|
||||
--font-size-2xl: 1.575rem;
|
||||
--font-size-3xl: 2.025rem;
|
||||
|
||||
/* Font weights */
|
||||
--font-weight-normal: 450;
|
||||
--font-weight-medium: 550;
|
||||
--font-weight-semibold: 650;
|
||||
--font-weight-bold: 750;
|
||||
|
||||
/* Royal Azure Solid Blue colors */
|
||||
--primary-blue: #0078D4;
|
||||
--primary-blue-dark: #005A9E;
|
||||
--primary-blue-darker: #004578;
|
||||
--primary-gradient: #0078D4;
|
||||
|
||||
/* UI colors */
|
||||
--bg-main: #F8FAFC;
|
||||
--bg-sidebar: #F1F5F9;
|
||||
--text-primary: #1E293B;
|
||||
--text-secondary: #475569;
|
||||
--text-muted: #94A3B8;
|
||||
--border-color: #E2E8F0;
|
||||
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
/* Warm neutral accents */
|
||||
--bg-warm: #faf8f5;
|
||||
--bg-warm-card: #f7f5f2;
|
||||
--border-warm: #e8e6e3;
|
||||
|
||||
/* Radius scale */
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 8px;
|
||||
|
||||
/* Semantic colors */
|
||||
--color-info: #0078D4;
|
||||
--color-danger: #DC2626;
|
||||
--color-danger-dark: #B91C1C;
|
||||
--color-success: #16A34A;
|
||||
--color-success-dark: #15803D;
|
||||
--color-secondary: #64748B;
|
||||
--color-secondary-dark: #475569;
|
||||
--bg-card: #FFFFFF;
|
||||
--bg-light: #f8f9fa;
|
||||
--border-light: #cbd5e1;
|
||||
--primary-blue-hover-bg: rgba(0, 120, 212, 0.06);
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
font-size: var(--font-size-base);
|
||||
background: var(--bg-main);
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg-main);
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
font-weight: var(--font-weight-normal);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* Prevent events in iframes */
|
||||
/* iframe{
|
||||
pointer-events: none;
|
||||
} */
|
||||
|
||||
/*
|
||||
ICONS
|
||||
*/
|
||||
.fa {
|
||||
margin-right: .5rem !important;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
SIDEBAR
|
||||
*/
|
||||
|
||||
div.sidebar {
|
||||
background: var(--bg-sidebar);
|
||||
border-right: 1px solid var(--border-color);
|
||||
border-left: 1px solid var(--border-color);
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
div.sidebar .nav-item a {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
color: var(--text-primary);
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-normal);
|
||||
transition: color 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
div.sidebar .nav-item a:hover {
|
||||
color: var(--primary-blue);
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
div.sidebar .nav-item a.active,
|
||||
div.sidebar .nav-item a:focus {
|
||||
color: var(--primary-blue);
|
||||
}
|
||||
|
||||
div.sidebar .nav-item h4 {
|
||||
font-size: var(--font-size-xs);
|
||||
text-transform: uppercase;
|
||||
font-weight: var(--font-weight-bold);
|
||||
margin-top: 15px;
|
||||
padding-left: 5px;
|
||||
color: var(--text-secondary);
|
||||
letter-spacing: 0.8px;
|
||||
}
|
||||
|
||||
/*
|
||||
QUICK SEARCH - SPOTLIGHT STYLE
|
||||
*/
|
||||
|
||||
/* Trigger Button */
|
||||
.quick-search-trigger {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
background: white;
|
||||
border: 2px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.quick-search-trigger:hover {
|
||||
border-color: var(--primary-blue);
|
||||
}
|
||||
|
||||
.quick-search-trigger .quick-search-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--primary-gradient);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick-search-trigger .quick-search-icon .fa {
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.quick-search-text {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
#hello-text {
|
||||
color: var(--text-primary);
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.quick-search-hint {
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
.quick-search-shortcut {
|
||||
padding: 6px 12px;
|
||||
background: var(--bg-main);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* Modal Overlay */
|
||||
.quick-search-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
display: none;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding-top: 15vh;
|
||||
}
|
||||
|
||||
.quick-search-modal.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.quick-search-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
animation: fadeIn 0.2s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
/* Modal Content */
|
||||
.quick-search-content {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
max-width: 680px;
|
||||
max-height: 80vh;
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-md);
|
||||
animation: slideDown 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px) scale(0.96);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.quick-search-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick-search-header .fa-search {
|
||||
color: var(--text-secondary);
|
||||
font-size: 22px;
|
||||
margin: 0 !important;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick-search-input {
|
||||
flex: 1;
|
||||
border: none !important;
|
||||
background: transparent !important;
|
||||
padding: 0 !important;
|
||||
font-size: var(--font-size-xl) !important;
|
||||
font-weight: var(--font-weight-normal) !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
.quick-search-input::placeholder {
|
||||
color: var(--text-muted) !important;
|
||||
font-size: var(--font-size-xl) !important;
|
||||
}
|
||||
|
||||
.quick-search-results {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
min-height: 150px;
|
||||
max-height: calc(80vh - 120px);
|
||||
}
|
||||
|
||||
.search-no-results {
|
||||
padding: 32px 24px;
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
|
||||
.search-suggestion {
|
||||
display: block;
|
||||
padding: 12px 16px;
|
||||
transition: background 0.15s ease;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.04);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.search-suggestion:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.search-suggestion:hover {
|
||||
background: var(--primary-blue-hover-bg);
|
||||
}
|
||||
|
||||
.search-suggestion .fa {
|
||||
color: var(--primary-blue);
|
||||
margin-right: 14px !important;
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.search-suggestion-item {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 6px;
|
||||
font-size: var(--font-size-lg);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.search-suggestion-options {
|
||||
font-size: var(--font-size-sm);
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.search-suggestion-options a {
|
||||
color: var(--primary-blue);
|
||||
margin-right: 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.search-suggestion-options a:hover {
|
||||
color: var(--primary-blue-dark);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
BOOTSTRAP Hacks
|
||||
*/
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
max-width: 1600px;
|
||||
}
|
||||
}
|
||||
|
||||
/* for small devices */
|
||||
@media (max-width: 575.98px) {
|
||||
|
||||
#jsmediaManagerButton,
|
||||
#jscategoryButton,
|
||||
#jsdescriptionButton {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.btn-light {
|
||||
color: #212529;
|
||||
background-color: #f3f3f3;
|
||||
border-color: #ced4d9;
|
||||
}
|
||||
|
||||
.btn-form {
|
||||
background-color: #F3F3F3;
|
||||
border-color: #DDD;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.btn-form:hover {
|
||||
background-color: rgb(228, 228, 228);
|
||||
border-color: #DDD;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
code {
|
||||
padding: 3px 5px 2px;
|
||||
margin: 0 1px;
|
||||
background: #eaeaea;
|
||||
background: rgba(0, 0, 0, .07);
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.list-group-sortable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
background-color: rgb(247, 247, 247);
|
||||
}
|
||||
|
||||
.modal-dialog .btn-link {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/*
|
||||
LOGIN
|
||||
*/
|
||||
|
||||
body.login {
|
||||
background: rgb(255, 255, 255);
|
||||
background: linear-gradient(0deg, rgba(255, 255, 255, 1) 0%, rgba(250, 250, 250, 1) 53%);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DASHBOARD
|
||||
*/
|
||||
|
||||
#dashboard ul.list-group.list-group-striped {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
background: var(--bg-card);
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li {
|
||||
border: none;
|
||||
overflow-wrap: anywhere;
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-normal);
|
||||
padding: 10px 18px;
|
||||
color: var(--text-primary);
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li:first-child {
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
padding: 14px 18px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li:first-child h4 {
|
||||
color: var(--text-primary);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-bold);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.6px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li:nth-of-type(even):not(:first-child) {
|
||||
background: var(--bg-light);
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li:hover:not(:first-child) {
|
||||
background: var(--primary-blue-hover-bg);
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li .notification-date {
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-xs);
|
||||
margin-top: 2px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#dashboard div.quick-links-icons {
|
||||
font-size: 2.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#dashboard a.quick-links {
|
||||
color: var(--text-secondary);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
#dashboard a.quick-links:hover {
|
||||
text-decoration: none;
|
||||
color: var(--primary-blue);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DASHBOARD METRIC CARDS
|
||||
*/
|
||||
|
||||
.card.metric-card {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
height: 100%;
|
||||
background: var(--bg-card);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.card.metric-card .card-body > .d-flex {
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.metric-card .card-body {
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.metric-card .card-title {
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.6px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-size: var(--font-size-2xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.2;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--text-muted);
|
||||
font-weight: var(--font-weight-medium);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.metric-card-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DASHBOARD ANALYTICS SECTION
|
||||
*/
|
||||
|
||||
.analytics-section {
|
||||
padding: 22px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--bg-card);
|
||||
}
|
||||
|
||||
#dashboard .analytics-section ul.list-group.list-group-striped {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#dashboard .analytics-section ul.list-group.list-group-striped li:first-child {
|
||||
padding: 0 0 12px 0;
|
||||
background: transparent;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/*
|
||||
ALERT
|
||||
*/
|
||||
|
||||
#alert {
|
||||
display: none;
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
border-radius: var(--radius-md);
|
||||
border: 0;
|
||||
z-index: 1000;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
margin: 0;
|
||||
font-size: var(--font-size-base);
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: var(--primary-gradient);
|
||||
border-left: none !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background: var(--color-danger);
|
||||
border-left: none !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
PLUGINS
|
||||
*/
|
||||
|
||||
.plugin-form label {
|
||||
display: block;
|
||||
margin-top: 1rem !important;
|
||||
}
|
||||
|
||||
.plugin-form input[type="text"],
|
||||
.plugin-form textarea,
|
||||
.plugin-form select {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
font-size: var(--font-size-base);
|
||||
line-height: 1.5;
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-card);
|
||||
background-clip: padding-box;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
transition: border-color .15s ease-in-out;
|
||||
}
|
||||
|
||||
.plugin-form textarea {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.plugin-form span.tip {
|
||||
display: block;
|
||||
font-size: 80%;
|
||||
font-weight: 400;
|
||||
margin-top: .25rem;
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
/*
|
||||
Manage > Content
|
||||
*/
|
||||
|
||||
td.child {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
/* Truncate the URL column with ellipsis when it doesn't fit. */
|
||||
td.contentURL a {
|
||||
display: inline-block;
|
||||
max-width: 30em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Kebab actions dropdown */
|
||||
.actionsDropdownToggle {
|
||||
line-height: 1;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.actionsDropdownToggle:focus,
|
||||
.actionsDropdownToggle:hover {
|
||||
text-decoration: none;
|
||||
color: var(--text-primary, #1E293B);
|
||||
}
|
||||
|
||||
.actionsDropdownToggle:focus-visible {
|
||||
outline: 2px solid var(--primary-blue);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.actionsDropdown .dropdown-item i.fa {
|
||||
width: 1.25em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
Manage > New Content
|
||||
*/
|
||||
|
||||
#jseditor {
|
||||
background: #fff;
|
||||
padding: 10px 5% !important;
|
||||
font-size: 16px;
|
||||
line-height: 1.5em;
|
||||
border: 1px solid #ced4da;
|
||||
}
|
||||
|
||||
#jseditorSidebar {
|
||||
display: none;
|
||||
height: calc(100% - 45px);
|
||||
width: 50%;
|
||||
max-width: 350px;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
top: 45px;
|
||||
right: 15px;
|
||||
background-color: #fff;
|
||||
overflow-x: hidden;
|
||||
transition: 0.5s;
|
||||
border-left: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
#jseditorSidebar {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#jseditorToolbarRight button {
|
||||
font-size: 0px !important;
|
||||
}
|
||||
|
||||
#jseditorToolbarRight button span {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.contentTools .btn {
|
||||
font-size: 0px !important;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.contentTools .btn span {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
#jseditorSidebar nav {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
|
||||
#jseditorSidebar nav a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#jseditorSidebar .nav-tabs .nav-link {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#jseditorSidebar .nav-link.active {
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: 3px solid #ccc;
|
||||
}
|
||||
|
||||
#jsshadow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: rgba(72, 72, 72, 0.7);
|
||||
z-index: 10;
|
||||
display: none;
|
||||
}
|
||||
|
||||
img.profilePicture {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* Switch button */
|
||||
.switch-button {
|
||||
font-size: 0.9em;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-icon-publish {
|
||||
color: #1cb11c;
|
||||
}
|
||||
|
||||
/* Subtle focus style for form elements */
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
select:focus,
|
||||
.form-control:focus,
|
||||
.custom-select:focus,
|
||||
.btn:focus {
|
||||
border-color: #b0bec5 !important;
|
||||
box-shadow: none !important;
|
||||
outline: none !important;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<script charset="utf-8">
|
||||
function showAlert(text) {
|
||||
console.log("[INFO] Function showAlert() called.");
|
||||
$("#alert").html(text);
|
||||
$("#alert").slideDown().delay(<?php echo ALERT_DISAPPEAR_IN*1000 ?>).slideUp();
|
||||
}
|
||||
|
||||
<?php if (Alert::defined()): ?>
|
||||
setTimeout(function(){ showAlert("<?php echo Alert::get() ?>") }, 500);
|
||||
<?php endif; ?>
|
||||
|
||||
$(window).click(function() {
|
||||
$("#alert").hide();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="alert" class="alert <?php echo (Alert::status()==ALERT_STATUS_FAIL)?'alert-danger':'alert-success' ?>"></div>
|
||||
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
// Preload the first chunk of files to avoid an AJAX round-trip the first time
|
||||
// the Media Manager is opened. Scans originals and resolves each thumbnail,
|
||||
// mirroring the shape returned by ajax/list-images.
|
||||
if (IMAGE_RESTRICT) {
|
||||
$mediaImagesPath = PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.DS;
|
||||
$mediaThumbnailsPath = PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.DS.'thumbnails'.DS;
|
||||
} else {
|
||||
$mediaImagesPath = PATH_UPLOADS;
|
||||
$mediaThumbnailsPath = PATH_UPLOADS_THUMBNAILS;
|
||||
}
|
||||
$listOfFilesByPage = mediaManagerListImages($mediaImagesPath, $mediaThumbnailsPath, MEDIA_MANAGER_NUMBER_OF_FILES);
|
||||
$preLoadFiles = !empty($listOfFilesByPage[0]) ? $listOfFilesByPage[0] : array();
|
||||
|
||||
// Amount of pages for the paginator
|
||||
$numberOfPages = count($listOfFilesByPage);
|
||||
?>
|
||||
|
||||
<div id="jsmediaManagerModal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col p-3">
|
||||
|
||||
<!--
|
||||
UPLOAD INPUT
|
||||
-->
|
||||
<h3 class="mt-2 mb-3"><i class="fa fa-image"></i> <?php $L->p('Images'); ?></h3>
|
||||
|
||||
<div id="jsalertMedia" class="alert alert-warning d-none" role="alert"></div>
|
||||
|
||||
<!-- Form and Input file -->
|
||||
<form name="bluditFormUpload" id="jsbluditFormUpload" enctype="multipart/form-data">
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="jsimages" name="images[]" multiple>
|
||||
<label class="custom-file-label" for="jsimages"><?php $L->p('Choose images to upload'); ?></label>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Progress bar -->
|
||||
<div class="progress mt-3">
|
||||
<div id="jsbluditProgressBar" class="progress-bar bg-primary" role="progressbar" style="width:0%"></div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
IMAGES LIST
|
||||
-->
|
||||
<!-- Table for list files -->
|
||||
<table id="jsbluditMediaTable" class="table mt-3">
|
||||
<tr>
|
||||
<td><?php $L->p('There are no images'); ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Paginator -->
|
||||
<nav id="jsbluditMediaTablePagination"></nav>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
<?php
|
||||
echo 'var preLoadFiles = '.json_encode($preLoadFiles).';';
|
||||
?>
|
||||
|
||||
function openMediaManager() {
|
||||
$('#jsmediaManagerModal').modal('show');
|
||||
}
|
||||
|
||||
function closeMediaManager() {
|
||||
$('#jsmediaManagerModal').modal('hide');
|
||||
}
|
||||
|
||||
// Remove all files from the table
|
||||
function cleanTable() {
|
||||
$('#jsbluditMediaTable').empty();
|
||||
}
|
||||
|
||||
function showMediaAlert(message) {
|
||||
$("#jsalertMedia").html(message).removeClass('d-none');
|
||||
}
|
||||
|
||||
function hideMediaAlert() {
|
||||
$("#jsalertMedia").addClass('d-none');
|
||||
}
|
||||
|
||||
// Show the files in the table
|
||||
function displayFiles(files, numberOfPages = <?= $numberOfPages ?>) {
|
||||
if (!Array.isArray(files)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clean table
|
||||
cleanTable();
|
||||
|
||||
// Regenerate the table
|
||||
if (files.length > 0) {
|
||||
$.each(files, function(key, item) {
|
||||
var filename = item.filename;
|
||||
var image = "<?php echo PAGE_IMAGES_URL; ?>"+filename;
|
||||
// item.thumbnail is empty when no thumbnail file exists (thumbnails
|
||||
// disabled, generation failed, format unsupported by GD). Fall back
|
||||
// to the original image so the preview never 404s.
|
||||
var thumbnail = item.thumbnail ? "<?php echo PAGE_THUMBNAILS_URL; ?>"+item.thumbnail : image;
|
||||
|
||||
tableRow = '<tr id="js'+filename+'">'+
|
||||
'<td style="width:80px"><img class="img-thumbnail" alt="200x200" src="'+thumbnail+'" style="width: 50px; height: 50px;"><\/td>'+
|
||||
'<td class="information">'+
|
||||
'<div class="text-secondary pb-2">'+filename+'<\/div>'+
|
||||
'<div>'+
|
||||
'<a href="#" class="mr-3 text-primary" onClick="editorInsertMedia(\''+image+'\'); closeMediaManager();"><i class="fa fa-plus-circle"></i><?php $L->p('Insert') ?><\/a>'+
|
||||
'<a href="#" class="mr-3 text-primary" onClick="editorInsertMedia(\''+thumbnail+'\'); closeMediaManager();"><i class="fa fa-image"></i><?php $L->p('Insert thumbnail') ?><\/a>'+
|
||||
'<a href="#" class="mr-3 text-primary" onClick="editorInsertLinkedMedia(\''+thumbnail+'\',\''+image+'\'); closeMediaManager();"><i class="fa fa-link"></i><?php $L->p('Insert linked thumbnail') ?><\/a>'+
|
||||
'<a href="#" class="text-primary" onClick="setCoverImage(\''+filename+'\'); closeMediaManager();"><i class="fa fa-desktop"></i><?php $L->p('Set as cover image') ?><\/a>'+
|
||||
'<a href="#" class="float-right text-danger" onClick="deleteMedia(\''+filename+'\')"><i class="fa fa-trash-o"></i><?php $L->p('Delete') ?><\/a>'+
|
||||
'<\/div>'+
|
||||
'<\/td>'+
|
||||
'<\/tr>';
|
||||
$('#jsbluditMediaTable').append(tableRow);
|
||||
});
|
||||
|
||||
mediaPagination = '<ul class="pagination justify-content-center flex-wrap">';
|
||||
for (var i = 1; i <= numberOfPages; i++) {
|
||||
mediaPagination += '<li class="page-item"><button type="button" class="btn btn-link page-link" onClick="getFiles('+i+')">'+i+'</button></li>';
|
||||
}
|
||||
mediaPagination += '</ul>';
|
||||
$('#jsbluditMediaTablePagination').html(mediaPagination);
|
||||
|
||||
}
|
||||
|
||||
if (files.length == 0) {
|
||||
$('#jsbluditMediaTable').html("<p><?php (IMAGE_RESTRICT ? $L->p('There are no images for the page') : $L->p('There are no images')) ?></p>");
|
||||
$('#jsbluditMediaTablePagination').html('');
|
||||
}
|
||||
}
|
||||
|
||||
// Get the list of files via AJAX, filter by the page number
|
||||
function getFiles(pageNumber) {
|
||||
$.post(HTML_PATH_ADMIN_ROOT+"ajax/list-images",
|
||||
{ tokenCSRF: tokenCSRF,
|
||||
pageNumber: pageNumber,
|
||||
uuid: "<?php echo PAGE_IMAGES_KEY ?>",
|
||||
path: "thumbnails" // the paths are defined in ajax/list-images
|
||||
},
|
||||
function(data) { // success function
|
||||
if (data.status==0) {
|
||||
displayFiles(data.files, data.numberOfPages);
|
||||
} else {
|
||||
console.log(data.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Delete the file and the thumbnail if exist
|
||||
function deleteMedia(filename) {
|
||||
$.post(HTML_PATH_ADMIN_ROOT+"ajax/delete-image",
|
||||
{ tokenCSRF: tokenCSRF,
|
||||
filename: filename,
|
||||
uuid: "<?php echo PAGE_IMAGES_KEY; ?>"
|
||||
},
|
||||
function(data) { // success function
|
||||
if (data.status==0) {
|
||||
getFiles(1);
|
||||
} else {
|
||||
console.log(data.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function setCoverImage(filename) {
|
||||
var image = "<?php echo PAGE_IMAGES_URL; ?>"+filename;
|
||||
$("#jscoverImage").val(filename);
|
||||
$("#jscoverImagePreview").attr("src", image);
|
||||
}
|
||||
|
||||
function uploadImages() {
|
||||
// Remove current alerts
|
||||
hideMediaAlert();
|
||||
|
||||
var images = $("#jsimages")[0].files;
|
||||
for (var i=0; i < images.length; i++) {
|
||||
// Check file type/extension
|
||||
const validImageTypes = ['image/gif', 'image/jpeg', 'image/png', 'image/svg+xml', 'image/webp'];
|
||||
if (!validImageTypes.includes(images[i].type)) {
|
||||
showMediaAlert("<?php echo $L->g('File type is not supported. Allowed types:').' '.implode(', ',$GLOBALS['ALLOWED_IMG_EXTENSION']) ?>");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check file size and compare with PHP upload_max_filesize
|
||||
if (images[i].size > UPLOAD_MAX_FILESIZE) {
|
||||
showMediaAlert("<?php echo $L->g('Maximum load file size allowed:').' '.ini_get('upload_max_filesize') ?>");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Clean progress bar
|
||||
$("#jsbluditProgressBar").removeClass().addClass("progress-bar bg-primary");
|
||||
$("#jsbluditProgressBar").width("0");
|
||||
|
||||
// Data to send via AJAX
|
||||
var formData = new FormData($("#jsbluditFormUpload")[0]);
|
||||
formData.append("uuid", "<?php echo PAGE_IMAGES_KEY ?>");
|
||||
formData.append("tokenCSRF", tokenCSRF);
|
||||
|
||||
$.ajax({
|
||||
url: HTML_PATH_ADMIN_ROOT+"ajax/upload-images",
|
||||
type: "POST",
|
||||
data: formData,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
xhr: function() {
|
||||
var xhr = $.ajaxSettings.xhr();
|
||||
if (xhr.upload) {
|
||||
xhr.upload.addEventListener("progress", function(e) {
|
||||
if (e.lengthComputable) {
|
||||
var percentComplete = (e.loaded / e.total)*100;
|
||||
$("#jsbluditProgressBar").width(percentComplete+"%");
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
return xhr;
|
||||
}
|
||||
}).done(function(data) {
|
||||
if (data.status==0) {
|
||||
$("#jsbluditProgressBar").removeClass("bg-primary").addClass("bg-success");
|
||||
// Get the files for the first page, including uploaded files
|
||||
getFiles(1);
|
||||
} else {
|
||||
$("#jsbluditProgressBar").removeClass("bg-primary").addClass("bg-danger");
|
||||
showMediaAlert(data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Display the files preloaded for the first time
|
||||
displayFiles(preLoadFiles);
|
||||
|
||||
// Select image event
|
||||
$("#jsimages").on("change", function(e) {
|
||||
uploadImages();
|
||||
});
|
||||
|
||||
// Drag and drop image
|
||||
$(window).on("dragover dragenter", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
openMediaManager();
|
||||
});
|
||||
|
||||
// Drag and drop image
|
||||
$(window).on("drop", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$("#jsimages").prop("files", e.originalEvent.dataTransfer.files);
|
||||
uploadImages();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,77 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark text-uppercase d-block d-lg-none">
|
||||
<div class="container">
|
||||
<span class="navbar-brand">
|
||||
<?php echo (defined('BLUDIT_PRO'))?'BLUDIT PRO':'BLUDIT' ?></span>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false"
|
||||
aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'dashboard' ?>">
|
||||
<?php $L->p('Dashboard') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ROOT ?>">
|
||||
<?php $L->p('Website') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'new-content' ?>">
|
||||
<?php $L->p('New content') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'content' ?>">
|
||||
<?php $L->p('Content') ?></a>
|
||||
</li>
|
||||
<?php if (!checkRole(array('admin'),false)): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'edit-user/'.$login->username() ?>">
|
||||
<?php $L->p('Profile') ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (checkRole(array('admin'),false)): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'categories' ?>">
|
||||
<?php $L->p('Categories') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'users' ?>">
|
||||
<?php $L->p('Users') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'settings' ?>">
|
||||
<?php $L->p('Settings') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'plugins' ?>">
|
||||
<?php $L->p('Plugins') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'themes' ?>">
|
||||
<?php $L->p('Themes') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'about' ?>">
|
||||
<?php $L->p('About') ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (checkRole(array('admin'),false)): ?>
|
||||
<?php
|
||||
if (!empty($plugins['adminSidebar'])) {
|
||||
foreach ($plugins['adminSidebar'] as $pluginSidebar) {
|
||||
echo '<li class="nav-item">';
|
||||
echo $pluginSidebar->adminSidebar();
|
||||
echo '</li>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php endif; ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'logout' ?>">
|
||||
<?php $L->p('Logout') ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,83 @@
|
||||
<!-- Use .flex-column to set a vertical direction -->
|
||||
<ul class="nav flex-column pt-4">
|
||||
|
||||
<li class="nav-item mb-4" style="display: flex; align-items: center;">
|
||||
<div style="display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; background: var(--primary-gradient); border-radius: 8px; box-shadow: var(--shadow-sm); flex-shrink: 0;">
|
||||
<img src="<?php echo HTML_PATH_CORE_IMG ?>logo.svg" width="18" height="18" alt="bludit-logo" style="filter: brightness(0) invert(1);">
|
||||
</div>
|
||||
<span style="margin-left: 10px; font-weight: 600; font-size: 1rem; color: var(--text-primary); line-height: 1;"><?php echo (defined('BLUDIT_PRO'))?'BLUDIT PRO':'BLUDIT' ?></span>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'dashboard' ?>"><span class="fa fa-dashboard"></span><?php $L->p('Dashboard') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" target="_blank" href="<?php echo HTML_PATH_ROOT ?>"><span class="fa fa-home"></span><?php $L->p('Website') ?></a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'new-content' ?>"><span class="fa fa-plus-circle text-primary"></span><?php $L->p('New content') ?></a>
|
||||
</li>
|
||||
|
||||
<?php if (!checkRole(array('admin'),false)): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'content' ?>"><span class="fa fa-archive"></span><?php $L->p('Content') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'edit-user/'.$login->username() ?>"><span class="fa fa-user"></span><?php $L->p('Profile') ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (checkRole(array('admin'),false)): ?>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<h4><?php $L->p('Manage') ?></h4>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'content' ?>"><span class="fa fa-folder"></span><?php $L->p('Content') ?></a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'categories' ?>"><span class="fa fa-bookmark"></span><?php $L->p('Categories') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'users' ?>"><span class="fa fa-users"></span><?php $L->p('Users') ?></a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<h4><?php $L->p('Settings') ?></h4>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'settings' ?>"><span class="fa fa-gear"></span><?php $L->p('General') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'plugins' ?>"><span class="fa fa-puzzle-piece"></span><?php $L->p('Plugins') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'themes' ?>"><span class="fa fa-desktop"></span><?php $L->p('Themes') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'about' ?>"><span class="fa fa-info"></span><?php $L->p('About') ?></a>
|
||||
</li>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (checkRole(array('admin', 'editor'),false)): ?>
|
||||
|
||||
<?php
|
||||
if (!empty($plugins['adminSidebar'])) {
|
||||
echo '<li class="nav-item"><hr></li>';
|
||||
foreach ($plugins['adminSidebar'] as $pluginSidebar) {
|
||||
echo '<li class="nav-item">';
|
||||
echo $pluginSidebar->adminSidebar();
|
||||
echo '</li>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<li class="nav-item mt-5">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'logout' ?>"><span class="fa fa-arrow-circle-right"></span><?php $L->p('Logout') ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,98 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><?php echo $layout['title'] ?></title>
|
||||
<meta charset="<?php echo CHARSET ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
<meta name="generator" content="Bludit">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="<?php echo HTML_PATH_CORE_IMG.'favicon.png?version='.BLUDIT_VERSION ?>">
|
||||
|
||||
<!-- CSS -->
|
||||
<?php
|
||||
echo Theme::cssBootstrap();
|
||||
echo Theme::cssLineAwesome();
|
||||
echo Theme::css(array(
|
||||
'bludit.css',
|
||||
'bludit.bootstrap.css'
|
||||
), DOMAIN_ADMIN_THEME_CSS);
|
||||
echo Theme::css(array(
|
||||
'jquery.datetimepicker.min.css',
|
||||
'select2.min.css',
|
||||
'select2-bootstrap4.min.css'
|
||||
), DOMAIN_CORE_CSS);
|
||||
?>
|
||||
|
||||
<!-- Javascript -->
|
||||
<?php
|
||||
echo Theme::jquery();
|
||||
echo Theme::jsBootstrap();
|
||||
echo Theme::jsSortable();
|
||||
echo Theme::js(array(
|
||||
'jquery.datetimepicker.full.min.js',
|
||||
'select2.full.min.js',
|
||||
'functions.js'
|
||||
), DOMAIN_CORE_JS, null);
|
||||
?>
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('adminHead') ?>
|
||||
|
||||
</head>
|
||||
<body class="h-100">
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('adminBodyBegin') ?>
|
||||
|
||||
<!-- Javascript dynamic generated by PHP -->
|
||||
<?php
|
||||
echo '<script charset="utf-8">'.PHP_EOL;
|
||||
include(PATH_CORE_JS.'variables.php');
|
||||
echo '</script>'.PHP_EOL;
|
||||
|
||||
echo '<script charset="utf-8">'.PHP_EOL;
|
||||
include(PATH_CORE_JS.'bludit-ajax.php');
|
||||
echo '</script>'.PHP_EOL;
|
||||
?>
|
||||
|
||||
<!-- Overlay background -->
|
||||
<div id="jsshadow"></div>
|
||||
|
||||
<!-- Alert -->
|
||||
<?php include('html/alert.php'); ?>
|
||||
|
||||
<!-- Navbar, only for small devices -->
|
||||
<?php include('html/navbar.php'); ?>
|
||||
|
||||
<div class="container min-vh-100">
|
||||
<!-- 25%/75% split on large devices, small, medium devices hide -->
|
||||
<div class="row min-vh-100 align-items-stretch">
|
||||
|
||||
<!-- LEFT SIDEBAR - Display only on large devices -->
|
||||
<div class="sidebar col-lg-2 d-none d-lg-block">
|
||||
<?php include('html/sidebar.php'); ?>
|
||||
</div>
|
||||
|
||||
<!-- RIGHT MAIN -->
|
||||
<div class="col-lg-10 pt-3 pb-1">
|
||||
<?php
|
||||
if (Sanitize::pathFile(PATH_ADMIN_VIEWS, $layout['view'].'.php')) {
|
||||
include(PATH_ADMIN_VIEWS.$layout['view'].'.php');
|
||||
} elseif ($layout['plugin'] && method_exists($layout['plugin'], 'adminView')) {
|
||||
echo $layout['plugin']->adminView();
|
||||
} else {
|
||||
echo '<h1 class="text-center">'.$L->g('Page not found').'</h1>';
|
||||
echo '<h2 class="text-center">'.$L->g('Choose a page from the sidebar.').'</h2>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('adminBodyEnd') ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
|
||||
class Bootstrap
|
||||
{
|
||||
|
||||
public static function modal($args)
|
||||
{
|
||||
|
||||
$buttonSecondary = $args['buttonSecondary'];
|
||||
$buttonSecondaryClass = $args['buttonSecondaryClass'];
|
||||
|
||||
$buttonPrimary = $args['buttonPrimary'];
|
||||
$buttonPrimaryClass = $args['buttonPrimaryClass'];
|
||||
|
||||
$modalText = $args['modalText'];
|
||||
$modalTitle = $args['modalTitle'];
|
||||
$modalId = $args['modalId'];
|
||||
|
||||
|
||||
return <<<EOF
|
||||
<div id="$modalId" class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<h3>$modalTitle</h3>
|
||||
<p>$modalText</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn $buttonSecondaryClass" data-dismiss="modal">$buttonSecondary</button>
|
||||
<button type="button" class="btn $buttonPrimaryClass">$buttonPrimary</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function link($args)
|
||||
{
|
||||
$options = 'href="' . $args['href'] . '"';
|
||||
if (isset($args['class'])) {
|
||||
$options .= ' class="' . $args['class'] . '"';
|
||||
}
|
||||
if (isset($args['target'])) {
|
||||
$options .= ' target="' . $args['target'] . '"';
|
||||
}
|
||||
|
||||
if (isset($args['icon'])) {
|
||||
return '<a ' . $options . '><span class="fa fa-' . $args['icon'] . '"></span>' . $args['title'] . '</a>';
|
||||
}
|
||||
|
||||
return '<a ' . $options . '>' . $args['title'] . '</a>';
|
||||
}
|
||||
|
||||
public static function pageTitle($args)
|
||||
{
|
||||
$icon = $args['icon'];
|
||||
$title = $args['title'];
|
||||
return <<<EOF
|
||||
<h2 class="mt-0 mb-3">
|
||||
<span class="fa fa-$icon" style="font-size: 0.9em;"></span><span>$title</span>
|
||||
</h2>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formOpen($args)
|
||||
{
|
||||
$class = empty($args['class']) ? '' : 'class="' . $args['class'] . '"';
|
||||
$id = empty($args['id']) ? '' : 'id="' . $args['id'] . '"';
|
||||
$enctype = empty($args['enctype']) ? '' : 'enctype="' . $args['enctype'] . '"';
|
||||
$action = empty($args['action']) ? 'action=""' : 'action="' . $args['action'] . '"';
|
||||
$method = empty($args['method']) ? 'method="post"' : 'method="' . $args['method'] . '"';
|
||||
$style = empty($args['style']) ? '' : 'style="' . $args['style'] . '"';
|
||||
|
||||
return <<<EOF
|
||||
<form $class $enctype $id $method $action $style autocomplete="off">
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formClose()
|
||||
{
|
||||
return <<<EOF
|
||||
</form>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Prevent the form submit when press enter key.
|
||||
$("form").keypress(function(e) {
|
||||
if ((e.which == 13) && (e.target.type !== "textarea")) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formTitle($args)
|
||||
{
|
||||
$title = $args['title'];
|
||||
return <<<EOF
|
||||
<h6 class="mt-4 mb-2 pb-2 border-bottom text-uppercase">$title</h6>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formInputTextBlock($args)
|
||||
{
|
||||
$name = $args['name'];
|
||||
$disabled = empty($args['disabled']) ? '' : 'disabled';
|
||||
$placeholder = isset($args['placeholder']) ? $args['placeholder'] : '';
|
||||
$value = isset($args['value']) ? $args['value'] : '';
|
||||
|
||||
$id = 'js' . $name;
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$tip = '';
|
||||
if (!empty($args['tip'])) {
|
||||
$tip = '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
|
||||
$class = 'form-group m-0';
|
||||
if (isset($args['class'])) {
|
||||
$class = $args['class'];
|
||||
}
|
||||
|
||||
$labelClass = 'mt-4 mb-2 pb-2 border-bottom text-uppercase w-100';
|
||||
if (isset($args['labelClass'])) {
|
||||
$labelClass = $args['labelClass'];
|
||||
}
|
||||
|
||||
$label = '';
|
||||
if (!empty($args['label'])) {
|
||||
$label = '<label class="' . $labelClass . '" for="' . $id . '">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$type = 'text';
|
||||
if (isset($args['type'])) {
|
||||
$type = $args['type'];
|
||||
}
|
||||
|
||||
return <<<EOF
|
||||
<div class="$class">
|
||||
$label
|
||||
<input type="text" dir="auto" value="$value" class="form-control" id="$id" name="$name" placeholder="$placeholder" $disabled>
|
||||
$tip
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formInputFile($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'custom-file';
|
||||
if (isset($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="' . $class . '">';
|
||||
$html .= '<input type="file" class="custom-file-input" id="' . $id . '">';
|
||||
$html .= '<label class="custom-file-label" for="' . $id . '">' . $args['label'] . '</label>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formTextarea($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'form-control';
|
||||
if (isset($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="form-group row">';
|
||||
|
||||
if (!empty($args['label'])) {
|
||||
$html .= '<label for="' . $id . '" class="col-sm-2 col-form-label">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$html .= '<div class="col-sm-10">';
|
||||
$html .= '<textarea class="' . $class . '" id="' . $id . '" name="' . $args['name'] . '" rows="' . $args['rows'] . '" placeholder="' . $args['placeholder'] . '">' . $args['value'] . '</textarea>';
|
||||
if (isset($args['tip'])) {
|
||||
$html .= '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formTextareaBlock($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'form-control';
|
||||
if (!empty($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="form-group m-0">';
|
||||
if (!empty($args['label'])) {
|
||||
$html .= '<label class="mt-4 mb-2 pb-2 border-bottom text-uppercase w-100" for="' . $id . '">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$html .= '<textarea class="' . $class . '" id="' . $id . '" name="' . $args['name'] . '" rows="' . $args['rows'] . '" placeholder="' . $args['placeholder'] . '">' . $args['value'] . '</textarea>';
|
||||
if (!empty($args['tip'])) {
|
||||
$html .= '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formInputText($args)
|
||||
{
|
||||
$name = $args['name'];
|
||||
$disabled = empty($args['disabled']) ? '' : 'disabled';
|
||||
$readonly = empty($args['readonly']) ? '' : 'readonly';
|
||||
$placeholder = isset($args['placeholder']) ? $args['placeholder'] : '';
|
||||
$value = isset($args['value']) ? $args['value'] : '';
|
||||
|
||||
$id = 'js' . $name;
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$tip = '';
|
||||
if (isset($args['tip'])) {
|
||||
$tip = '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
|
||||
$label = '';
|
||||
if (isset($args['label'])) {
|
||||
$label = '<label for="' . $id . '" class="col-sm-2 col-form-label">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$class = 'form-control';
|
||||
if (isset($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$type = 'text';
|
||||
if (isset($args['type'])) {
|
||||
$type = $args['type'];
|
||||
}
|
||||
|
||||
return <<<EOF
|
||||
<div class="form-group row">
|
||||
$label
|
||||
<div class="col-sm-10">
|
||||
<input class="$class" id="$id" name="$name" value="$value" placeholder="$placeholder" type="$type" dir="auto" $disabled $readonly>
|
||||
$tip
|
||||
</div>
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formCheckbox($args)
|
||||
{
|
||||
$labelForCheckbox = isset($args['labelForCheckbox']) ? $args['labelForCheckbox'] : '';
|
||||
$placeholder = isset($args['placeholder']) ? $args['placeholder'] : '';
|
||||
$tip = isset($args['tip']) ? '<small class="form-text text-muted">' . $args['tip'] . '</small>' : '';
|
||||
$value = isset($args['value']) ? $args['value'] : '';
|
||||
$name = $args['name'];
|
||||
$id = 'js' . $name;
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
$disabled = isset($args['disabled']) ? 'disabled' : '';
|
||||
|
||||
$class = 'form-group m-0';
|
||||
if (isset($args['class'])) {
|
||||
$class = $args['class'];
|
||||
}
|
||||
|
||||
$labelClass = 'mt-4 mb-2 pb-2 border-bottom text-uppercase w-100';
|
||||
if (isset($args['labelClass'])) {
|
||||
$labelClass = $args['labelClass'];
|
||||
}
|
||||
|
||||
$type = 'text';
|
||||
if (isset($args['type'])) {
|
||||
$type = $args['type'];
|
||||
}
|
||||
|
||||
$label = '';
|
||||
if (!empty($args['label'])) {
|
||||
$label = '<label class="' . $labelClass . '">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$checked = $args['checked'] ? 'checked' : '';
|
||||
$value = $checked ? '1' : '0';
|
||||
|
||||
return <<<EOF
|
||||
<div class="$class">
|
||||
$label
|
||||
<div class="form-check">
|
||||
<input type="hidden" name="$name" value="$value"><input id="$id" type="checkbox" class="form-check-input" onclick="this.previousSibling.value=1-this.previousSibling.value" $checked>
|
||||
<label class="form-check-label" for="$id">$labelForCheckbox</label>
|
||||
$tip
|
||||
</div>
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formSelect($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'custom-select';
|
||||
if (isset($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="form-group row">';
|
||||
|
||||
if (isset($args['label'])) {
|
||||
$html .= '<label for="' . $id . '" class="col-sm-2 col-form-label">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$html .= '<div class="col-sm-10">';
|
||||
$html .= '<select id="' . $id . '" name="' . $args['name'] . '" class="' . $class . '">';
|
||||
foreach ($args['options'] as $key => $value) {
|
||||
$html .= '<option ' . (($key == $args['selected']) ? 'selected' : '') . ' value="' . $key . '">' . $value . '</option>';
|
||||
}
|
||||
$html .= '</select>';
|
||||
if (isset($args['tip'])) {
|
||||
$html .= '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formSelectBlock($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'custom-select';
|
||||
if (!empty($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="form-group m-0">';
|
||||
|
||||
if (!empty($args['label'])) {
|
||||
$html .= '<label class="mt-4 mb-2 pb-2 border-bottom text-uppercase w-100" for="' . $id . '">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$html .= '<select id="' . $id . '" name="' . $args['name'] . '" class="' . $class . '">';
|
||||
if (!empty($args['emptyOption'])) {
|
||||
$html .= '<option value="">' . $args['emptyOption'] . '</option>';
|
||||
}
|
||||
foreach ($args['options'] as $key => $value) {
|
||||
$html .= '<option ' . (($key == $args['selected']) ? 'selected' : '') . ' value="' . $key . '">' . $value . '</option>';
|
||||
}
|
||||
$html .= '</select>';
|
||||
if (!empty($args['tip'])) {
|
||||
$html .= '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formInputHidden($args)
|
||||
{
|
||||
return '<input type="hidden" id="js' . $args['name'] . '" name="' . $args['name'] . '" value="' . $args['value'] . '">';
|
||||
}
|
||||
|
||||
public static function alert($args)
|
||||
{
|
||||
$class = 'alert';
|
||||
if (!empty($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$text = $args['text'];
|
||||
|
||||
return <<<EOF
|
||||
<div class="$class" role="alert">$text</div>
|
||||
EOF;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title><?php echo (defined('BLUDIT_PRO') ? $site->title() : 'BLUDIT') ?> - Login</title>
|
||||
<meta charset="<?php echo CHARSET ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="<?php echo HTML_PATH_CORE_IMG . 'favicon.png?version=' . BLUDIT_VERSION ?>">
|
||||
|
||||
<!-- CSS -->
|
||||
<?php
|
||||
echo Theme::cssBootstrap();
|
||||
echo Theme::css(array(
|
||||
'bludit.css',
|
||||
'bludit.bootstrap.css'
|
||||
), DOMAIN_ADMIN_THEME_CSS);
|
||||
?>
|
||||
|
||||
<style>
|
||||
body.login {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, #1e88e5 0%, #1565c0 50%, #0d47a1 100%);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
|
||||
padding: 40px;
|
||||
animation: fadeInUp 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.login-logo .logo-icon {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%);
|
||||
border-radius: 16px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 8px 20px rgba(21, 101, 192, 0.4);
|
||||
}
|
||||
|
||||
.login-logo .logo-icon img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.login-logo .logo-icon.custom-logo {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 150px;
|
||||
max-height: 80px;
|
||||
}
|
||||
|
||||
.login-logo .logo-icon.custom-logo img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 150px;
|
||||
max-height: 80px;
|
||||
filter: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.login-logo h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a2e;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.login-logo p {
|
||||
color: #6c757d;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.login-card .form-control {
|
||||
border: 2px solid #e9ecef;
|
||||
border-radius: 10px;
|
||||
padding: 12px 16px;
|
||||
font-size: 0.95rem;
|
||||
transition: all 0.3s ease;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.login-card .form-control:focus {
|
||||
border-color: #1e88e5;
|
||||
box-shadow: 0 0 0 4px rgba(30, 136, 229, 0.15);
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.login-card .form-control::placeholder {
|
||||
color: #adb5bd;
|
||||
}
|
||||
|
||||
.login-card .form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-card .form-group label {
|
||||
font-weight: 500;
|
||||
color: #495057;
|
||||
margin-bottom: 10px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.login-card .btn-login {
|
||||
background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%);
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
padding: 12px 18px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
width: 100%;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(21, 101, 192, 0.4);
|
||||
}
|
||||
|
||||
.login-card .btn-login:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(21, 101, 192, 0.5);
|
||||
}
|
||||
|
||||
.login-card .btn-login:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.login-card .form-check {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.login-card .form-check-input {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-top: 0;
|
||||
border: 2px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.login-card .form-check-input:checked {
|
||||
background-color: #1e88e5;
|
||||
border-color: #1e88e5;
|
||||
}
|
||||
|
||||
.login-card .form-check-label {
|
||||
color: #6c757d;
|
||||
font-size: 0.9rem;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.login-footer p {
|
||||
color: #6c757d;
|
||||
font-size: 0.85rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.login-footer a {
|
||||
color: #1e88e5;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Alert styles for login page */
|
||||
.login-alert {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 1050;
|
||||
min-width: 300px;
|
||||
max-width: 90%;
|
||||
border-radius: 10px;
|
||||
padding: 12px 20px;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
animation: slideDown 0.4s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.login-alert.alert-danger {
|
||||
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a5a 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 4px 15px rgba(238, 90, 90, 0.4);
|
||||
}
|
||||
|
||||
.login-alert.alert-success {
|
||||
background: linear-gradient(135deg, #51cf66 0%, #40c057 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 4px 15px rgba(64, 192, 87, 0.4);
|
||||
}
|
||||
|
||||
/* Input icons */
|
||||
.input-icon-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.input-icon-wrapper .form-control {
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
.input-icon-wrapper .input-icon {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #adb5bd;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.input-icon-wrapper .form-control:focus + .input-icon,
|
||||
.input-icon-wrapper .form-control:not(:placeholder-shown) + .input-icon {
|
||||
color: #1e88e5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Javascript -->
|
||||
<?php
|
||||
echo Theme::jquery();
|
||||
echo Theme::jsBootstrap();
|
||||
?>
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('loginHead') ?>
|
||||
</head>
|
||||
|
||||
<body class="login">
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('loginBodyBegin') ?>
|
||||
|
||||
<!-- Alert -->
|
||||
<?php if (Alert::defined()): ?>
|
||||
<div id="login-alert" class="login-alert alert <?php echo (Alert::status() == ALERT_STATUS_FAIL) ? 'alert-danger' : 'alert-success' ?>">
|
||||
<?php echo Alert::get() ?>
|
||||
</div>
|
||||
<script>
|
||||
setTimeout(function() {
|
||||
document.getElementById('login-alert').style.display = 'none';
|
||||
}, <?php echo ALERT_DISAPPEAR_IN * 1000 ?>);
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="login-container">
|
||||
<div class="login-card">
|
||||
<?php
|
||||
if (Sanitize::pathFile(PATH_ADMIN_VIEWS, $layout['view'] . '.php')) {
|
||||
include(PATH_ADMIN_VIEWS . $layout['view'] . '.php');
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('loginBodyEnd') ?>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="pattern-0" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" viewBox="0 0 100 100">
|
||||
<path d="M 0 0 L 50 0 L 50 100 L 0 100 Z" style="fill: black;"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<path style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0); stroke-miterlimit: 4; stroke-dasharray: none; stroke-width: 24.1239;" d="M 140.612 16.07 C 136.565 10.367 125.853 69.255 108.381 129.061 C 103.577 145.502 110.407 162.089 112.885 176.473 C 117.048 183.779 121.184 194.444 124.691 207.736 C 125.873 212.214 126.903 216.775 127.823 221.339 C 118.109 245.954 112.626 273.846 112.626 303.409 C 112.626 330.642 117.299 356.445 125.623 379.586 C 141.303 391.431 156.518 408.669 169.013 430.093 C 174.86 440.118 179.69 450.381 183.539 460.577 C 203.547 475.159 226.618 483.493 251.189 483.493 C 274.393 483.493 296.256 476.068 315.472 462.963 C 319.453 451.983 324.113 440.618 330.877 430.093 C 344.265 409.265 360.773 389.253 377.633 377.13 C 389.314 358.536 390.837 330.762 389.75 303.409 C 388.621 275.027 384.678 248.146 375.666 224.253 C 376.446 218.449 377.415 212.643 378.618 206.935 C 381.644 192.557 385.537 181.154 389.621 173.676 C 391.233 159.61 396.683 143.363 391.511 127.64 C 370.872 64.898 373.494 118.034 367.485 123.062 C 359.888 129.421 319.716 67.053 321.298 129.061 C 321.471 135.825 321.836 142.432 322.359 148.856 C 301.557 132.637 276.381 152.664 250.36 152.664 C 223.685 152.664 199.605 133.116 178.463 150.095 C 178.74 142.832 178.79 135.327 178.593 127.64 C 177.01 65.631 165.781 51.533 140.612 16.07 Z" id="path2987"/>
|
||||
<path id="path3763" d="M 248.613 379.622 C 238.675 379.622 215.913 399.093 215.913 412.414 C 215.913 416.062 217.038 419.515 219.042 422.614 C 222.816 424.2 226.478 426.509 229.486 429.38 C 230.893 430.722 232.055 432.096 232.981 433.462 C 237.797 435.415 243.351 436.53 249.265 436.53 C 254.852 436.53 260.114 435.536 264.738 433.78 C 265.698 432.311 266.929 430.827 268.446 429.38 C 271.669 426.304 275.642 423.875 279.701 422.286 C 281.573 419.274 282.618 415.932 282.618 412.414 C 282.618 399.093 259.202 379.622 248.613 379.622 Z" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0); stroke-miterlimit: 4; stroke-dasharray: none; stroke-width: 24.1239;"/>
|
||||
<path style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0); stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-width: 24.1239;" d="M 218.799 311.887 C 253.953 253.834 192.034 175.403 161.146 240.701 C 147.314 269.942 179.823 338.489 218.799 311.887 Z" id="path3779"/>
|
||||
<path style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0); stroke-miterlimit: 4; stroke-width: 18;" d="M 311.951 273.021 C 311.951 278.795 306.666 283.478 300.147 283.478 C 293.629 283.478 288.343 278.795 288.343 273.021 C 288.343 267.245 293.629 262.563 300.147 262.563 C 306.666 262.563 311.951 267.245 311.951 273.021 Z" id="path3785"/>
|
||||
<path style="stroke: rgb(0, 0, 0); stroke-miterlimit: 4; fill: rgb(255, 255, 255); stroke-width: 24.1239;" d="M 229.289 269.988 C 229.289 285.489 216.409 298.058 200.518 298.058 C 184.631 298.058 171.749 285.489 171.749 269.988 C 171.749 254.478 184.631 241.912 200.518 241.912 C 216.409 241.912 229.289 254.478 229.289 269.988 Z" id="path-1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
Reference in New Issue
Block a user