This commit is contained in:
Ty Clifford
2026-07-03 07:31:09 -04:00
commit cebb0d3af1
800 changed files with 89782 additions and 0 deletions
@@ -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);
}
+800
View File
@@ -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>
+269
View File
@@ -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>
+98
View File
@@ -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>
+403
View File
@@ -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;
}
}
+312
View File
@@ -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>
+13
View File
@@ -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