Updates
This commit is contained in:
19
nextcloud-aio/php/public/automatic_reload.js
Normal file
19
nextcloud-aio/php/public/automatic_reload.js
Normal file
@@ -0,0 +1,19 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
if (document.hasFocus()) {
|
||||
// hide reload button if the site reloads automatically
|
||||
let list = document.getElementsByClassName("reload button");
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
// list[i] is a node with the desired class name
|
||||
list[i].style.display = 'none';
|
||||
}
|
||||
|
||||
// set timeout for reload
|
||||
setTimeout(function(){
|
||||
window.location.reload(1);
|
||||
}, 5000);
|
||||
} else {
|
||||
window.addEventListener("beforeunload", function() {
|
||||
document.getElementById('overlay').classList.add('loading')
|
||||
});
|
||||
}
|
||||
});
|
||||
3
nextcloud-aio/php/public/before-unload.js
Normal file
3
nextcloud-aio/php/public/before-unload.js
Normal file
@@ -0,0 +1,3 @@
|
||||
window.addEventListener("beforeunload", function() {
|
||||
document.getElementById('overlay').classList.add('loading')
|
||||
});
|
||||
88
nextcloud-aio/php/public/containers-form-submit.js
Normal file
88
nextcloud-aio/php/public/containers-form-submit.js
Normal file
@@ -0,0 +1,88 @@
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Hide submit button initially
|
||||
const optionsFormSubmit = document.getElementById("options-form-submit");
|
||||
optionsFormSubmit.style.display = 'none';
|
||||
|
||||
const communityFormSubmit = document.getElementById("community-form-submit");
|
||||
communityFormSubmit.style.display = 'none';
|
||||
|
||||
// Store initial states for all checkboxes
|
||||
const initialStateOptionsContainers = {};
|
||||
const initialStateCommunityContainers = {};
|
||||
const optionsContainersCheckboxes = document.querySelectorAll("#options-form input[type='checkbox']");
|
||||
const communityContainersCheckboxes = document.querySelectorAll("#community-form input[type='checkbox']");
|
||||
|
||||
optionsContainersCheckboxes.forEach(checkbox => {
|
||||
initialStateOptionsContainers[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state
|
||||
});
|
||||
|
||||
communityContainersCheckboxes.forEach(checkbox => {
|
||||
initialStateCommunityContainers[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state
|
||||
});
|
||||
|
||||
// Function to compare current states to initial states
|
||||
function checkForOptionContainerChanges() {
|
||||
let hasChanges = false;
|
||||
|
||||
optionsContainersCheckboxes.forEach(checkbox => {
|
||||
if (checkbox.checked !== initialStateOptionsContainers[checkbox.id]) {
|
||||
hasChanges = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Show or hide submit button based on changes
|
||||
optionsFormSubmit.style.display = hasChanges ? 'block' : 'none';
|
||||
}
|
||||
|
||||
// Function to compare current states to initial states
|
||||
function checkForCommunityContainerChanges() {
|
||||
let hasChanges = false;
|
||||
|
||||
communityContainersCheckboxes.forEach(checkbox => {
|
||||
if (checkbox.checked !== initialStateCommunityContainers[checkbox.id]) {
|
||||
hasChanges = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Show or hide submit button based on changes
|
||||
communityFormSubmit.style.display = hasChanges ? 'block' : 'none';
|
||||
}
|
||||
|
||||
// Event listener to trigger visibility check on each change
|
||||
optionsContainersCheckboxes.forEach(checkbox => {
|
||||
checkbox.addEventListener("change", checkForOptionContainerChanges);
|
||||
});
|
||||
|
||||
communityContainersCheckboxes.forEach(checkbox => {
|
||||
checkbox.addEventListener("change", checkForCommunityContainerChanges);
|
||||
});
|
||||
|
||||
// Custom behaviors for specific options
|
||||
function handleTalkVisibility() {
|
||||
const talkRecording = document.getElementById("talk-recording");
|
||||
if (document.getElementById("talk").checked) {
|
||||
talkRecording.disabled = false;
|
||||
} else {
|
||||
talkRecording.checked = false;
|
||||
talkRecording.disabled = true;
|
||||
}
|
||||
checkForOptionContainerChanges(); // Check changes after toggling Talk Recording
|
||||
}
|
||||
|
||||
function handleDockerSocketProxyWarning() {
|
||||
if (document.getElementById("docker-socket-proxy").checked) {
|
||||
alert('⚠️ Warning! Enabling this container comes with possible Security problems since you are exposing the docker socket and all its privileges to the Nextcloud container. Enable this only if you are sure what you are doing!');
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize event listeners for specific behaviors
|
||||
document.getElementById("talk").addEventListener('change', handleTalkVisibility);
|
||||
document.getElementById("docker-socket-proxy").addEventListener('change', handleDockerSocketProxyWarning);
|
||||
|
||||
// Initialize talk-recording visibility on page load
|
||||
handleTalkVisibility(); // Ensure talk-recording is correctly initialized
|
||||
|
||||
// Initial call to check for changes
|
||||
checkForOptionContainerChanges();
|
||||
checkForCommunityContainerChanges();
|
||||
});
|
||||
5
nextcloud-aio/php/public/disable-clamav.js
Normal file
5
nextcloud-aio/php/public/disable-clamav.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Clamav
|
||||
let clamav = document.getElementById("clamav");
|
||||
clamav.disabled = true;
|
||||
});
|
||||
5
nextcloud-aio/php/public/disable-collabora.js
Normal file
5
nextcloud-aio/php/public/disable-collabora.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Collabora
|
||||
let collabora = document.getElementById("collabora");
|
||||
collabora.disabled = true;
|
||||
});
|
||||
7
nextcloud-aio/php/public/disable-docker-socket-proxy.js
Normal file
7
nextcloud-aio/php/public/disable-docker-socket-proxy.js
Normal file
@@ -0,0 +1,7 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Docker socket proxy
|
||||
let dockerSocketProxy = document.getElementById("docker-socket-proxy");
|
||||
if (dockerSocketProxy) {
|
||||
dockerSocketProxy.disabled = true;
|
||||
}
|
||||
});
|
||||
5
nextcloud-aio/php/public/disable-fulltextsearch.js
Normal file
5
nextcloud-aio/php/public/disable-fulltextsearch.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Fulltextsearch
|
||||
let fulltextsearch = document.getElementById("fulltextsearch");
|
||||
fulltextsearch.disabled = true;
|
||||
});
|
||||
5
nextcloud-aio/php/public/disable-imaginary.js
Normal file
5
nextcloud-aio/php/public/disable-imaginary.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Imaginary
|
||||
let imaginary = document.getElementById("imaginary");
|
||||
imaginary.disabled = true;
|
||||
});
|
||||
7
nextcloud-aio/php/public/disable-onlyoffice.js
Normal file
7
nextcloud-aio/php/public/disable-onlyoffice.js
Normal file
@@ -0,0 +1,7 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// OnlyOffice
|
||||
let onlyoffice = document.getElementById("onlyoffice");
|
||||
if (onlyoffice) {
|
||||
onlyoffice.disabled = true;
|
||||
}
|
||||
});
|
||||
4
nextcloud-aio/php/public/disable-talk-recording.js
Normal file
4
nextcloud-aio/php/public/disable-talk-recording.js
Normal file
@@ -0,0 +1,4 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Talk-recording
|
||||
document.getElementById("talk-recording").disabled = true;
|
||||
});
|
||||
5
nextcloud-aio/php/public/disable-talk.js
Normal file
5
nextcloud-aio/php/public/disable-talk.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Talk
|
||||
let talk = document.getElementById("talk");
|
||||
talk.disabled = true;
|
||||
});
|
||||
5
nextcloud-aio/php/public/disable-whiteboard.js
Normal file
5
nextcloud-aio/php/public/disable-whiteboard.js
Normal file
@@ -0,0 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Whiteboard
|
||||
let whiteboard = document.getElementById("whiteboard");
|
||||
whiteboard.disabled = true;
|
||||
});
|
||||
90
nextcloud-aio/php/public/forms.js
Normal file
90
nextcloud-aio/php/public/forms.js
Normal file
@@ -0,0 +1,90 @@
|
||||
"use strict";
|
||||
|
||||
function showPassword(id) {
|
||||
let passwordField = document.getElementById(id);
|
||||
if (passwordField.type === "password" && passwordField.value !== "") {
|
||||
passwordField.type = "text";
|
||||
} else if (passwordField.type === "text" && passwordField.value === "") {
|
||||
passwordField.type = "password";
|
||||
}
|
||||
}
|
||||
|
||||
(function (){
|
||||
let lastError;
|
||||
|
||||
function showError(message) {
|
||||
const body = document.getElementsByTagName('body')[0]
|
||||
const toast = document.createElement("div")
|
||||
toast.className = "toast error"
|
||||
toast.prepend(message)
|
||||
if (lastError) {
|
||||
lastError.remove()
|
||||
}
|
||||
lastError = toast
|
||||
body.prepend(toast)
|
||||
setTimeout(toast.remove.bind(toast), 10000)
|
||||
}
|
||||
|
||||
function handleEvent(e) {
|
||||
const xhr = e.target;
|
||||
if (xhr.status === 201) {
|
||||
window.location.replace(xhr.getResponseHeader('Location'));
|
||||
} else if (xhr.status === 422) {
|
||||
disableSpinner()
|
||||
showError(xhr.response);
|
||||
} else if (xhr.status === 500) {
|
||||
showError("Server error. Please check the mastercontainer logs for details. This page will reload after 10s automatically. Then you can check the mastercontainer logs.");
|
||||
// Reload after 10s since it is expected that the updated view is shown (e.g. after starting containers)
|
||||
setTimeout(function(){
|
||||
window.location.reload(1);
|
||||
}, 10000);
|
||||
} else {
|
||||
// If the responose is not one of the above, we should reload to show the latest content
|
||||
window.location.reload(1);
|
||||
}
|
||||
}
|
||||
|
||||
function enableSpinner() {
|
||||
document.getElementById('overlay').classList.add('loading');
|
||||
}
|
||||
|
||||
function disableSpinner() {
|
||||
document.getElementById('overlay').classList.remove('loading');
|
||||
}
|
||||
|
||||
function initForm(form) {
|
||||
function submit(event)
|
||||
{
|
||||
if (lastError) {
|
||||
lastError.remove()
|
||||
}
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.addEventListener('load', handleEvent);
|
||||
xhr.addEventListener('error', () => showError("Failed to talk to server."));
|
||||
xhr.addEventListener('error', () => disableSpinner());
|
||||
xhr.open(form.method, form.getAttribute("action"));
|
||||
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
enableSpinner();
|
||||
xhr.send(new URLSearchParams(new FormData(form)));
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
form.onsubmit = submit;
|
||||
console.info(form);
|
||||
}
|
||||
|
||||
function initForms() {
|
||||
const forms = document.querySelectorAll('form.xhr')
|
||||
console.info("Making " + forms.length + " form(s) use XHR.");
|
||||
for (const form of forms) {
|
||||
initForm(form);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
// Loading hasn't finished yet
|
||||
document.addEventListener('DOMContentLoaded', initForms);
|
||||
} else { // `DOMContentLoaded` has already fired
|
||||
initForms();
|
||||
}
|
||||
})()
|
||||
BIN
nextcloud-aio/php/public/img/favicon.png
Normal file
BIN
nextcloud-aio/php/public/img/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
BIN
nextcloud-aio/php/public/img/jo-myoung-hee-fluid-dark.webp
Normal file
BIN
nextcloud-aio/php/public/img/jo-myoung-hee-fluid-dark.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
BIN
nextcloud-aio/php/public/img/jo-myoung-hee-fluid.webp
Normal file
BIN
nextcloud-aio/php/public/img/jo-myoung-hee-fluid.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
4
nextcloud-aio/php/public/img/nextcloud-logo.svg
Normal file
4
nextcloud-aio/php/public/img/nextcloud-logo.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg id="nextcloud-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 142 100" width="142" height="100">
|
||||
<g id="logo" stroke="currentColor" fill="none" stroke-width="11" transform="scale(1.109)"><circle cx="20" cy="32" r="13"/><circle cx="64" cy="32" r="23"/><circle cx="108" cy="32" r="13"/></g>
|
||||
<g id="Nextcloud" fill="currentColor" transform="translate(-3.4, -3.4) scale(1.17)"><path d="M15.4,67.4c-0.4,0-0.5,0.2-0.5,0.6v14.6c0,0.4,0.2,0.5,0.5,0.5h0.4c0.4,0,0.5-0.2,0.5-0.5V70.4 l7.9,12.3c0,0.1,0.1,0.1,0.1,0.1c0,0,0,0,0,0c0,0,0.1,0,0.1,0.1c0,0,0,0,0.1,0c0,0,0,0,0,0c0.1,0,0.1,0,0.2,0h0.4 c0.4,0,0.5-0.2,0.5-0.5V68c0-0.4-0.2-0.6-0.5-0.6h-0.4c-0.4,0-0.6,0.2-0.6,0.6v12.1l-7.9-12.3c0,0-0.1-0.1-0.1-0.1 c-0.1-0.1-0.2-0.2-0.4-0.2L15.4,67.4z M110.8,67.6c-0.4,0-0.2,0.2-0.2,0.6v5c0,0.5,0,0.9,0,0.9h0c0,0-1-2.2-3.6-2.2 c-2.9,0-5,2.3-4.9,5.7c0,3.4,1.9,5.8,4.8,5.8c2.9,0,3.8-2.3,3.8-2.3h0.1c0,0-0.1,0.3-0.1,0.7v0.9c0,0.4,0.2,0.5,0.6,0.5h0.4 c0.4,0,0.5-0.2,0.5-0.6V68.2c0-0.4-0.6-0.6-0.9-0.6H110.8z M71.8,67.7c-0.4,0-0.1,0.2-0.1,0.6v12.3c0,2.4,1.6,2.7,2.5,2.7 c0.4,0,0.6-0.2,0.6-0.6v-0.4c0-0.4-0.2-0.5-0.5-0.5c-0.5-0.1-1.2-0.2-1.2-1.6v-12c0-0.4-0.6-0.6-0.9-0.6L71.8,67.7z M53.8,69 c-0.4,0-0.6,0.2-0.6,0.6v2.6v1.3v5.7c0,2.6,1.5,4.1,3.9,4.1c0.5,0,0.6-0.1,0.6-0.5v-0.3c0-0.4-0.1-0.5-0.6-0.6 c-0.9-0.1-2.4-0.4-2.4-2.9v-5.5h2.3c0.4,0,0.6-0.1,0.6-0.5v-0.2c0-0.4-0.2-0.6-0.6-0.6h-2.3v-2.6c0-0.4-0.1-0.6-0.5-0.6L53.8,69z M33.8,71.8c-3,0-5.4,2.2-5.5,5.8c0,3.4,2.5,5.8,5.8,5.8c1.8,0,3.1-0.8,3.7-1.2c0.3-0.2,0.3-0.5,0.2-0.7l-0.2-0.2 c-0.2-0.3-0.4-0.4-0.7-0.2c-0.5,0.4-1.5,1-2.9,1c-2.3,0-4.2-1.6-4.3-4.4h8c0.3,0,0.6-0.3,0.6-0.6C38.4,73.9,36.8,71.8,33.8,71.8z M65,71.8c-3.3,0-5.8,2.4-5.8,5.8c0,3.4,2.5,5.8,5.8,5.8c2,0,3.4-1,3.9-1.4c0.3-0.3,0.3-0.5,0.1-0.8L68.8,81 c-0.2-0.3-0.4-0.4-0.7-0.2C67.6,81.3,66.6,82,65,82c-2.4,0-4.3-1.8-4.3-4.4c0-2.7,1.9-4.5,4.3-4.5c1.3,0,2.3,0.7,2.8,1 c0.3,0.2,0.6,0.2,0.8-0.1l0.2-0.3c0.3-0.3,0.2-0.6-0.1-0.8C68.1,72.6,66.9,71.8,65,71.8L65,71.8z M81.9,71.8 c-3.2,0-5.8,2.5-5.8,5.7c0,3.3,2.6,5.8,5.8,5.8c3.2,0,5.8-2.5,5.8-5.8C87.8,74.3,85.1,71.8,81.9,71.8z M49.5,72 c-0.1,0-0.2,0.1-0.4,0.2l-2,2.4l-1.5,1.8l-2.3-2.7L42,72.2c-0.1-0.1-0.2-0.2-0.4-0.2c-0.1,0-0.3,0-0.4,0.2l-0.3,0.3 c-0.3,0.2-0.3,0.5,0,0.7l2,2.4l1.7,2l-2.5,2.9c0,0,0,0,0,0L40.9,82c-0.2,0.3-0.2,0.6,0.1,0.8l0.3,0.3c0.3,0.2,0.5,0.2,0.7-0.1 l2-2.4l1.5-1.8l2.3,2.7c0,0,0,0,0,0l1.2,1.5c0.2,0.3,0.5,0.3,0.8,0.1l0.3-0.3c0.3-0.2,0.3-0.5,0-0.7l-2-2.4l-1.7-2l2.5-2.9 c0,0,0,0,0,0l1.2-1.5c0.2-0.3,0.2-0.6-0.1-0.8l-0.3-0.3C49.7,72,49.6,71.9,49.5,72L49.5,72z M90.7,72c-0.4,0-0.5,0.2-0.5,0.6v6.5 c0,2.9,2.1,4.3,4.7,4.3c2.6,0,4.7-1.4,4.7-4.3v-6.5c0.1-0.4-0.1-0.6-0.5-0.6h-0.4c-0.4,0-0.6,0.2-0.6,0.6v6.1 c0,1.7-1.1,3.3-3.3,3.3c-2.1,0-3.3-1.6-3.3-3.3v-6.1c0-0.4-0.2-0.6-0.6-0.6L90.7,72z M33.8,73c1.6,0,3,1.2,3.1,3.5h-6.9 C30.3,74.3,31.9,73,33.8,73z M81.9,73.1c2.4,0,4.3,1.9,4.3,4.4c0,2.6-1.9,4.5-4.3,4.5c-2.4,0-4.3-2-4.3-4.5 C77.6,75.1,79.6,73.1,81.9,73.1z M107.1,73.1c2.4,0,3.5,2.2,3.5,4.4c0,3.2-1.7,4.5-3.6,4.5c-2.1,0-3.5-1.8-3.5-4.5 C103.5,74.8,105.1,73.1,107.1,73.1z"/></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
198
nextcloud-aio/php/public/index.php
Normal file
198
nextcloud-aio/php/public/index.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// increase memory limit to 2GB
|
||||
ini_set('memory_limit', '2048M');
|
||||
|
||||
// set max execution time to 2h just in case of a very slow internet connection
|
||||
ini_set('max_execution_time', '7200');
|
||||
|
||||
// Log whole log messages
|
||||
ini_set('log_errors_max_len', '0');
|
||||
|
||||
use DI\Container;
|
||||
use Slim\Csrf\Guard;
|
||||
use Slim\Factory\AppFactory;
|
||||
use Slim\Views\Twig;
|
||||
use Slim\Views\TwigMiddleware;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$container = \AIO\DependencyInjection::GetContainer();
|
||||
$dataConst = $container->get(\AIO\Data\DataConst::class);
|
||||
ini_set('session.save_path', $dataConst->GetSessionDirectory());
|
||||
|
||||
// Auto logout on browser close
|
||||
ini_set('session.cookie_lifetime', '0');
|
||||
|
||||
# Keep session for 24h max
|
||||
ini_set('session.gc_maxlifetime', '86400');
|
||||
|
||||
// Create app
|
||||
AppFactory::setContainer($container);
|
||||
$app = AppFactory::create();
|
||||
$responseFactory = $app->getResponseFactory();
|
||||
|
||||
// Register Middleware On Container
|
||||
$container->set(Guard::class, function () use ($responseFactory) {
|
||||
$guard = new Guard($responseFactory);
|
||||
$guard->setPersistentTokenMode(true);
|
||||
return $guard;
|
||||
});
|
||||
|
||||
// Register Middleware To Be Executed On All Routes
|
||||
session_start();
|
||||
$app->add(Guard::class);
|
||||
|
||||
// Create Twig
|
||||
$twig = Twig::create(__DIR__ . '/../templates/', ['cache' => false]);
|
||||
$app->add(TwigMiddleware::create($app, $twig));
|
||||
$twig->addExtension(new \AIO\Twig\CsrfExtension($container->get(Guard::class)));
|
||||
|
||||
// Auth Middleware
|
||||
$app->add(new \AIO\Middleware\AuthMiddleware($container->get(\AIO\Auth\AuthManager::class)));
|
||||
|
||||
// API
|
||||
$app->post('/api/docker/watchtower', AIO\Controller\DockerController::class . ':StartWatchtowerContainer');
|
||||
$app->get('/api/docker/getwatchtower', AIO\Controller\DockerController::class . ':StartWatchtowerContainer');
|
||||
$app->post('/api/docker/start', AIO\Controller\DockerController::class . ':StartContainer');
|
||||
$app->post('/api/docker/backup', AIO\Controller\DockerController::class . ':StartBackupContainerBackup');
|
||||
$app->post('/api/docker/backup-check', AIO\Controller\DockerController::class . ':StartBackupContainerCheck');
|
||||
$app->post('/api/docker/backup-check-repair', AIO\Controller\DockerController::class . ':StartBackupContainerCheckRepair');
|
||||
$app->post('/api/docker/backup-test', AIO\Controller\DockerController::class . ':StartBackupContainerTest');
|
||||
$app->post('/api/docker/restore', AIO\Controller\DockerController::class . ':StartBackupContainerRestore');
|
||||
$app->post('/api/docker/stop', AIO\Controller\DockerController::class . ':StopContainer');
|
||||
$app->get('/api/docker/logs', AIO\Controller\DockerController::class . ':GetLogs');
|
||||
$app->post('/api/auth/login', AIO\Controller\LoginController::class . ':TryLogin');
|
||||
$app->get('/api/auth/getlogin', AIO\Controller\LoginController::class . ':GetTryLogin');
|
||||
$app->post('/api/auth/logout', AIO\Controller\LoginController::class . ':Logout');
|
||||
$app->post('/api/configuration', \AIO\Controller\ConfigurationController::class . ':SetConfig');
|
||||
|
||||
// Views
|
||||
$app->get('/containers', function (Request $request, Response $response, array $args) use ($container) {
|
||||
$view = Twig::fromRequest($request);
|
||||
$view->addExtension(new \AIO\Twig\ClassExtension());
|
||||
/** @var \AIO\Data\ConfigurationManager $configurationManager */
|
||||
$configurationManager = $container->get(\AIO\Data\ConfigurationManager::class);
|
||||
/** @var \AIO\Docker\DockerActionManager $dockerActionManger */
|
||||
$dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
|
||||
/** @var \AIO\Controller\DockerController $dockerController */
|
||||
$dockerController = $container->get(\AIO\Controller\DockerController::class);
|
||||
$dockerActionManger->ConnectMasterContainerToNetwork();
|
||||
$dockerController->StartDomaincheckContainer();
|
||||
|
||||
// Check if bypass_mastercontainer_update is provided on the URL, a special developer mode to bypass a mastercontainer update and use local image.
|
||||
$params = $request->getQueryParams();
|
||||
$bypass_mastercontainer_update = isset($params['bypass_mastercontainer_update']);
|
||||
$bypass_container_update = isset($params['bypass_container_update']);
|
||||
|
||||
return $view->render($response, 'containers.twig', [
|
||||
'domain' => $configurationManager->GetDomain(),
|
||||
'apache_port' => $configurationManager->GetApachePort(),
|
||||
'borg_backup_host_location' => $configurationManager->GetBorgBackupHostLocation(),
|
||||
'borg_remote_repo' => $configurationManager->GetBorgRemoteRepo(),
|
||||
'borg_public_key' => $configurationManager->GetBorgPublicKey(),
|
||||
'nextcloud_password' => $configurationManager->GetAndGenerateSecret('NEXTCLOUD_PASSWORD'),
|
||||
'containers' => (new \AIO\ContainerDefinitionFetcher($container->get(\AIO\Data\ConfigurationManager::class), $container))->FetchDefinition(),
|
||||
'borgbackup_password' => $configurationManager->GetAndGenerateSecret('BORGBACKUP_PASSWORD'),
|
||||
'is_mastercontainer_update_available' => ( $bypass_mastercontainer_update ? false : $dockerActionManger->IsMastercontainerUpdateAvailable() ),
|
||||
'has_backup_run_once' => $configurationManager->hasBackupRunOnce(),
|
||||
'is_backup_container_running' => $dockerActionManger->isBackupContainerRunning(),
|
||||
'backup_exit_code' => $dockerActionManger->GetBackupcontainerExitCode(),
|
||||
'is_instance_restore_attempt' => $configurationManager->isInstanceRestoreAttempt(),
|
||||
'borg_backup_mode' => $configurationManager->GetBorgBackupMode(),
|
||||
'was_start_button_clicked' => $configurationManager->wasStartButtonClicked(),
|
||||
'has_update_available' => $dockerActionManger->isAnyUpdateAvailable(),
|
||||
'last_backup_time' => $configurationManager->GetLastBackupTime(),
|
||||
'backup_times' => $configurationManager->GetBackupTimes(),
|
||||
'current_channel' => $dockerActionManger->GetCurrentChannel(),
|
||||
'is_clamav_enabled' => $configurationManager->isClamavEnabled(),
|
||||
'is_onlyoffice_enabled' => $configurationManager->isOnlyofficeEnabled(),
|
||||
'is_collabora_enabled' => $configurationManager->isCollaboraEnabled(),
|
||||
'is_talk_enabled' => $configurationManager->isTalkEnabled(),
|
||||
'borg_restore_password' => $configurationManager->GetBorgRestorePassword(),
|
||||
'daily_backup_time' => $configurationManager->GetDailyBackupTime(),
|
||||
'is_daily_backup_running' => $configurationManager->isDailyBackupRunning(),
|
||||
'timezone' => $configurationManager->GetTimezone(),
|
||||
'skip_domain_validation' => $configurationManager->shouldDomainValidationBeSkipped(),
|
||||
'talk_port' => $configurationManager->GetTalkPort(),
|
||||
'collabora_dictionaries' => $configurationManager->GetCollaboraDictionaries(),
|
||||
'collabora_additional_options' => $configurationManager->GetAdditionalCollaboraOptions(),
|
||||
'automatic_updates' => $configurationManager->areAutomaticUpdatesEnabled(),
|
||||
'is_backup_section_enabled' => $configurationManager->isBackupSectionEnabled(),
|
||||
'is_imaginary_enabled' => $configurationManager->isImaginaryEnabled(),
|
||||
'is_fulltextsearch_enabled' => $configurationManager->isFulltextsearchEnabled(),
|
||||
'additional_backup_directories' => $configurationManager->GetAdditionalBackupDirectoriesString(),
|
||||
'nextcloud_datadir' => $configurationManager->GetNextcloudDatadirMount(),
|
||||
'nextcloud_mount' => $configurationManager->GetNextcloudMount(),
|
||||
'nextcloud_upload_limit' => $configurationManager->GetNextcloudUploadLimit(),
|
||||
'nextcloud_max_time' => $configurationManager->GetNextcloudMaxTime(),
|
||||
'nextcloud_memory_limit' => $configurationManager->GetNextcloudMemoryLimit(),
|
||||
'is_dri_device_enabled' => $configurationManager->isDriDeviceEnabled(),
|
||||
'is_nvidia_gpu_enabled' => $configurationManager->isNvidiaGpuEnabled(),
|
||||
'is_talk_recording_enabled' => $configurationManager->isTalkRecordingEnabled(),
|
||||
'is_docker_socket_proxy_enabled' => $configurationManager->isDockerSocketProxyEnabled(),
|
||||
'is_whiteboard_enabled' => $configurationManager->isWhiteboardEnabled(),
|
||||
'community_containers' => $configurationManager->listAvailableCommunityContainers(),
|
||||
'community_containers_enabled' => $configurationManager->GetEnabledCommunityContainers(),
|
||||
'bypass_container_update' => $bypass_container_update,
|
||||
]);
|
||||
})->setName('profile');
|
||||
$app->get('/login', function (Request $request, Response $response, array $args) use ($container) {
|
||||
$view = Twig::fromRequest($request);
|
||||
/** @var \AIO\Docker\DockerActionManager $dockerActionManger */
|
||||
$dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
|
||||
return $view->render($response, 'login.twig', [
|
||||
'is_login_allowed' => $dockerActionManger->isLoginAllowed(),
|
||||
]);
|
||||
});
|
||||
$app->get('/setup', function (Request $request, Response $response, array $args) use ($container) {
|
||||
$view = Twig::fromRequest($request);
|
||||
/** @var \AIO\Data\Setup $setup */
|
||||
$setup = $container->get(\AIO\Data\Setup::class);
|
||||
|
||||
if(!$setup->CanBeInstalled()) {
|
||||
return $view->render(
|
||||
$response,
|
||||
'already-installed.twig'
|
||||
);
|
||||
}
|
||||
|
||||
return $view->render(
|
||||
$response,
|
||||
'setup.twig',
|
||||
[
|
||||
'password' => $setup->Setup(),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
// Auth Redirector
|
||||
$app->get('/', function (\Psr\Http\Message\RequestInterface $request, Response $response, array $args) use ($container) {
|
||||
/** @var \AIO\Auth\AuthManager $authManager */
|
||||
$authManager = $container->get(\AIO\Auth\AuthManager::class);
|
||||
|
||||
/** @var \AIO\Data\Setup $setup */
|
||||
$setup = $container->get(\AIO\Data\Setup::class);
|
||||
if($setup->CanBeInstalled()) {
|
||||
return $response
|
||||
->withHeader('Location', '/setup')
|
||||
->withStatus(302);
|
||||
}
|
||||
|
||||
if($authManager->IsAuthenticated()) {
|
||||
return $response
|
||||
->withHeader('Location', '/containers')
|
||||
->withStatus(302);
|
||||
} else {
|
||||
return $response
|
||||
->withHeader('Location', '/login')
|
||||
->withStatus(302);
|
||||
}
|
||||
});
|
||||
|
||||
$errorMiddleware = $app->addErrorMiddleware(false, true, true);
|
||||
|
||||
$app->run();
|
||||
2
nextcloud-aio/php/public/robots.txt
Normal file
2
nextcloud-aio/php/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
12
nextcloud-aio/php/public/second-tab-warning.js
Normal file
12
nextcloud-aio/php/public/second-tab-warning.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const channel = new BroadcastChannel('tab')
|
||||
|
||||
channel.postMessage('second-tab')
|
||||
// note that listener is added after posting the message
|
||||
|
||||
channel.addEventListener('message', (msg) => {
|
||||
if (msg.data === 'second-tab') {
|
||||
// message received from 2nd tab
|
||||
document.getElementById('overlay').classList.add('loading')
|
||||
alert('Cannot open multiple instances. You can use AIO here by reloading the page.')
|
||||
}
|
||||
});
|
||||
551
nextcloud-aio/php/public/style.css
Normal file
551
nextcloud-aio/php/public/style.css
Normal file
@@ -0,0 +1,551 @@
|
||||
:root {
|
||||
--color-nextcloud-blue: #0082c9;
|
||||
--color-nextcloud-logo: var(--color-nextcloud-blue);
|
||||
--color-main-background: white;
|
||||
--color-input-background: white;
|
||||
--color-main-text: black;
|
||||
--color-main-border: black;
|
||||
--color-main-border-hover: var(--color-main-border);
|
||||
--color-error: #db0606;
|
||||
--color-error-hover: #df2525;
|
||||
--color-error-text: #c20505;
|
||||
--color-success: #46ba61;
|
||||
--color-running: #ffd000;
|
||||
--color-primary-element: #00679e;
|
||||
--color-primary-element-hover: #005a8a;
|
||||
--color-primary-element-text: #ffffff;
|
||||
--color-primary-element-light: #e5eff5;
|
||||
--color-primary-element-light-hover: #dbe4ea;
|
||||
--color-primary-element-light-text: #00293f;
|
||||
--color-border-maxcontrast: #7d7d7d;
|
||||
--color-loader: #f3f3f3;
|
||||
--color-disabled: #d3d3d3; /* light gray background for disabled checkboxes */
|
||||
--color-border-disabled: #a9a9a9; /* darker gray border for disabled checkboxes */
|
||||
--color-text-disabled: #a9a9a9; /* matching label text color for disabled checkboxes */
|
||||
--border: .5px;
|
||||
--border-hover: 2px;
|
||||
--border-radius: 7px;
|
||||
--border-radius-large: 12px;
|
||||
--default-font-size: 13px;
|
||||
--checkbox-size: 16px;
|
||||
--max-width: 500px;
|
||||
--container-top-margin: 20px;
|
||||
--container-bottom-margin: 20px;
|
||||
--container-padding: 2px;
|
||||
--container-height-calculation-difference: calc(var(--container-top-margin) + var(--container-bottom-margin));
|
||||
--main-height-calculation-difference: calc(var(--container-height-calculation-difference) + calc(var(--container-padding) * 2));
|
||||
--main-padding: 50px;
|
||||
}
|
||||
|
||||
/* Breakpoint calculation: 500px (max-width) + 100px (main-padding * 2) + 200px (additional space) = 800px
|
||||
Note: Unfortunately, it's not possible to calculate this dynamically using CSS variables in media queries */
|
||||
@media only screen and (max-width: 800px) {
|
||||
:root {
|
||||
--container-top-margin: 50px;
|
||||
--container-bottom-margin: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--color-main-background: #171717;
|
||||
--color-input-background: #ebebeb;
|
||||
--color-main-text: #ebebeb;
|
||||
--color-nextcloud-logo: var(--color-main-text);
|
||||
--color-main-border: var(--color-border-maxcontrast);
|
||||
--color-main-border-hover: var(--color-main-text);
|
||||
--color-error: #ff3333;
|
||||
--color-error-hover: #ff6666;
|
||||
--color-error-text: #ff8080;
|
||||
--color-primary-element:#0091f2;
|
||||
--color-primary-element-hover:#079cff;
|
||||
--color-primary-element-text:#000000;
|
||||
--color-primary-element-light:#14232c;
|
||||
--color-primary-element-light-hover:#1e2d35;
|
||||
--color-primary-element-light-text:#99d3f9;
|
||||
--color-loader: var(--color-border-maxcontrast);
|
||||
--border-hover: var(--border);
|
||||
}
|
||||
|
||||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Oxygen-Sans, Cantarell, Ubuntu, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
background-color: var(--color-main-background);
|
||||
color: var(--color-main-text);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--color-primary-element);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--color-primary-element-hover);
|
||||
}
|
||||
|
||||
a.button,
|
||||
input[type="submit"] {
|
||||
padding: 8px 16px;
|
||||
width: auto;
|
||||
height: 34px;
|
||||
cursor: pointer;
|
||||
background-color: var(--color-primary-element);
|
||||
font-weight: bold;
|
||||
border-radius: var(--border-radius);
|
||||
margin: 3px 3px 3px 0;
|
||||
font-size: var(--default-font-size);
|
||||
color: var(--color-primary-element-text);
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a.button:focus,
|
||||
input[type="submit"]:focus {
|
||||
outline: 2px solid var(--color-main-border);
|
||||
}
|
||||
|
||||
a.button:hover,
|
||||
input[type="submit"]:hover {
|
||||
background-color: var(--color-primary-element-hover);
|
||||
}
|
||||
|
||||
|
||||
a.button.light:hover,
|
||||
input[type="submit"].light:hover {
|
||||
background-color: var(--color-primary-element-light);
|
||||
color: var(--color-primary-element-light-text);
|
||||
}
|
||||
|
||||
|
||||
a.button.light,
|
||||
input[type="submit"].light {
|
||||
background-color: var(--color-primary-element-light);
|
||||
}
|
||||
|
||||
a.button.error,
|
||||
input[type="submit"].error {
|
||||
background-color: var(--color-error);
|
||||
}
|
||||
|
||||
a.button.error:hover,
|
||||
input[type="submit"].error:hover {
|
||||
background-color: var(--color-error-hover);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
padding-bottom: 5px;
|
||||
text-indent: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
span.error {
|
||||
background-color: var(--color-error);
|
||||
}
|
||||
|
||||
div.toast.error {
|
||||
border-left-color: var(--color-error);
|
||||
}
|
||||
|
||||
.status {
|
||||
display: inline-block;
|
||||
height: var(--checkbox-size);
|
||||
width: var(--checkbox-size);
|
||||
vertical-align: text-bottom;
|
||||
border-radius: 50%
|
||||
}
|
||||
|
||||
span.success {
|
||||
background-color: var(--color-success);
|
||||
}
|
||||
|
||||
span.running {
|
||||
background-color: var(--color-running);
|
||||
}
|
||||
|
||||
div.toast.success {
|
||||
border-left-color: var(--color-success);
|
||||
}
|
||||
|
||||
div.toast {
|
||||
border-left: 3px solid;
|
||||
right: 10px;
|
||||
min-width: 200px;
|
||||
box-shadow: 0 0 6px 0 rgba(77, 77, 77, 0.3);
|
||||
padding: 12px;
|
||||
margin-top: 45px;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--color-main-background) none;
|
||||
color: var(--color-main-text);
|
||||
}
|
||||
|
||||
.nextcloud-logo {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
color: var(--color-nextcloud-logo);
|
||||
}
|
||||
|
||||
.fallback-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg:not(:has(use)) .fallback-text {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.login {
|
||||
padding: 50px;
|
||||
background-color: var(--color-main-background);
|
||||
color: var(--color-main-text);
|
||||
width: 500px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: var(--border-radius-large);
|
||||
}
|
||||
|
||||
.login > .monospace {
|
||||
font-family: monospace, monospace, system-ui, -apple-system, 'Segoe UI', Roboto, Oxygen-Sans, Cantarell, Ubuntu, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.login > form > input[type="password"],
|
||||
.login > form > input[type="text"],
|
||||
.login > form > input[type="submit"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login > img {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.login a.button,
|
||||
.login input[type="submit"] {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding: 0px;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
min-height: 100dvh;
|
||||
min-width: 100vw;
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
background-image: url("img/jo-myoung-hee-fluid.webp");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .wrapper {
|
||||
background-image: url("img/jo-myoung-hee-fluid-dark.webp");
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
select {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
height: 34px;
|
||||
margin-bottom: 15px;
|
||||
border-radius: var(--border-radius);
|
||||
border: var(--border) solid var(--color-border-maxcontrast);
|
||||
background: var(--color-main-background);
|
||||
color: var(--color-main-text);
|
||||
}
|
||||
|
||||
input[type="text"]:hover,
|
||||
input[type="password"]:hover,
|
||||
select:hover {
|
||||
border: var(--border-hover) solid var(--color-main-border-hover);
|
||||
}
|
||||
|
||||
textarea {
|
||||
border-radius: var(--border-radius);
|
||||
border: .5px solid var(--color-main-border);
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
input[type="text"]:focus,
|
||||
input[type="password"]:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border: 1px solid var(--color-main-border);
|
||||
}
|
||||
|
||||
/* Scroll bar for dark mode */
|
||||
html[data-theme="dark"] ::-webkit-scrollbar {
|
||||
width: 8px; /* Width of the scroll bar */
|
||||
}
|
||||
|
||||
html[data-theme="dark"] ::-webkit-scrollbar-thumb {
|
||||
background-color: #444; /* Dark mode scrollbar thumb color */
|
||||
border-radius: 4px; /* Rounded corners for the thumb */
|
||||
}
|
||||
|
||||
html[data-theme="dark"] ::-webkit-scrollbar-track {
|
||||
background-color: #333; /* Dark mode scrollbar track color */
|
||||
}
|
||||
|
||||
/* Scroll bar for light mode */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px; /* Width of the scroll bar */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #888; /* Light mode scrollbar thumb color */
|
||||
border-radius: 4px; /* Rounded corners for the thumb */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: #f0f0f0; /* Light mode scrollbar track color */
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: var(--container-top-margin) auto var(--container-bottom-margin) auto;
|
||||
padding: var(--container-padding);
|
||||
max-width: calc(var(--max-width) + calc(var(--main-padding) * 2) + 8px);
|
||||
background-color: var(--color-main-background);
|
||||
border-radius: var(--border-radius-large);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
max-height: calc(100dvh - var(--container-height-calculation-difference));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-left: var(--main-padding);
|
||||
padding-right: var(--main-padding);
|
||||
background-color: transparent; /* transparent, since color comes from outer container */
|
||||
color: var(--color-main-text);
|
||||
max-height: calc(100dvh - var(--main-height-calculation-difference));
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
word-break: break-word;
|
||||
max-width: calc(var(--max-width) + calc(var(--main-padding) * 2));
|
||||
margin: 0 auto;
|
||||
padding-bottom: var(--main-padding);
|
||||
}
|
||||
|
||||
.logo {
|
||||
color: white;
|
||||
height: 50px;
|
||||
width: 62px;
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 1px;
|
||||
bottom: 1px;
|
||||
}
|
||||
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
height: 50px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
padding: 0 20px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
header > form {
|
||||
margin-left: auto;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
/* Standard styling for enabled checkboxes */
|
||||
input[type="checkbox"]:not(:disabled) {
|
||||
width: var(--checkbox-size);
|
||||
height: var(--checkbox-size);
|
||||
-webkit-appearance: none; /* remove default styling */
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: 1px solid var(--color-primary-element);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
vertical-align: middle; /* align checkbox vertically with text */
|
||||
margin-top: -1px; /* adjust for better alignment */
|
||||
}
|
||||
|
||||
/* Hover effects for enabled checkboxes */
|
||||
input[type="checkbox"]:not(:disabled):hover {
|
||||
border-color: var(--color-primary-element-hover);
|
||||
}
|
||||
|
||||
/* Checkmark styling for enabled checkboxes */
|
||||
input[type="checkbox"]:checked:not(:disabled) {
|
||||
background-color: var(--color-primary-element);
|
||||
border-color: var(--color-border-maxcontrast);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked:not(:disabled)::after {
|
||||
content: ''; /* Creates a pseudo-element for the checkmark */
|
||||
position: absolute; /* Positions it absolutely */
|
||||
left: 4px; /* Positioning of the checkmark */
|
||||
top: 0; /* Positioning of the checkmark */
|
||||
width: 4px; /* Width of the checkmark */
|
||||
height: 9px; /* Height of the checkmark */
|
||||
border: solid white; /* Color of the checkmark */
|
||||
border-width: 0 2px 3px 0; /* Creates the checkmark shape */
|
||||
transform: rotate(45deg); /* Rotates to form a checkmark */
|
||||
}
|
||||
|
||||
/* Styling for disabled checkboxes (grayed out, no hover, no pointer) */
|
||||
input[type="checkbox"]:disabled:not(:checked) {
|
||||
background-color: var(--color-disabled);
|
||||
border-color: var(--color-border-disabled);
|
||||
cursor: default;
|
||||
opacity: 0.5; /* Makes the checkbox appear faded */
|
||||
}
|
||||
|
||||
/* Styling for disabled checked checkboxes (no pointer) */
|
||||
input[type="checkbox"]:disabled:checked {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:disabled:hover {
|
||||
border-color: var(--color-border-disabled); /* Keeps disabled state without hover effect */
|
||||
}
|
||||
|
||||
/* General Label styling */
|
||||
label {
|
||||
cursor: pointer;
|
||||
margin-left: 4px;
|
||||
line-height: var(--checkbox-size);
|
||||
}
|
||||
|
||||
/* Label cursor for disabled checkboxes */
|
||||
input[type="checkbox"]:disabled + label {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Label styling for disabled, not checked checkboxes */
|
||||
input[type="checkbox"]:disabled:not(:checked) + label {
|
||||
color: var(--color-text-disabled);
|
||||
}
|
||||
|
||||
.loading {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
#overlay {
|
||||
position: fixed; /* Sit on top of the page content */
|
||||
display: none; /* Hidden by default */
|
||||
width: 100%; /* Full width (cover the whole page) */
|
||||
height: 100%; /* Full height (cover the whole page) */
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5); /* Black background with opacity */
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#overlay.loading {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loader {
|
||||
border: 16px solid var(--color-loader);
|
||||
border-radius: 50%;
|
||||
border-top: 16px solid var(--color-nextcloud-blue);
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
-webkit-animation: spin 2s linear infinite; /* Safari */
|
||||
animation: spin 2s linear infinite;
|
||||
position: absolute;
|
||||
top: calc(50% - 60px);
|
||||
left: calc(50% - 60px);
|
||||
}
|
||||
|
||||
/* Safari */
|
||||
@-webkit-keyframes spin {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* General theme button styling */
|
||||
#theme-toggle {
|
||||
position: fixed; /* Keep the button in the same position */
|
||||
right: 30px; /* Adjust the distance from the right */
|
||||
bottom: 30px; /* Adjust the distance from the bottom */
|
||||
background-color: transparent; /* Make the background transparent */
|
||||
border: none; /* Remove border */
|
||||
font-size: 36px; /* Adjust font size */
|
||||
cursor: pointer; /* Change cursor to pointer */
|
||||
outline: none;
|
||||
z-index: 9999; /* Ensures the icon is on top of every layer */
|
||||
}
|
||||
|
||||
/* Icon styling: default state */
|
||||
#theme-icon {
|
||||
display: inline-block;
|
||||
border-radius: 50%; /* Round shape */
|
||||
position: relative; /* For the pseudo-element positioning */
|
||||
transition: box-shadow 0.3s, background-color 0.3s; /* Smooth transition for hover effect */
|
||||
opacity: 0.6; /* Slightly transparent by default */
|
||||
filter: grayscale(100%); /* Make the icon black and white */
|
||||
}
|
||||
|
||||
/* Create the inner glow effect with ::after */
|
||||
#theme-icon::after {
|
||||
content: ''; /* Empty content for the pseudo-element */
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0px; /* Invisible dot */
|
||||
height: 0px; /* Invisible dot */
|
||||
background-color: transparent; /* Invisible by default */
|
||||
border-radius: 50%; /* Circle shape */
|
||||
transform: translate(-50%, -50%); /* Center the dot */
|
||||
transition: box-shadow 0.3s, background-color 0.3s; /* Smooth transition for hover */
|
||||
}
|
||||
|
||||
/* Hover effect for both light and dark modes */
|
||||
#theme-toggle:hover #theme-icon {
|
||||
position: relative; /* Ensures stacking order */
|
||||
filter: grayscale(0%); /* Restore full color */
|
||||
opacity: 1; /* Fully visible on hover */
|
||||
}
|
||||
|
||||
/* Inner glow when hovered */
|
||||
#theme-toggle:hover #theme-icon::after {
|
||||
box-shadow: 0 0 40px 40px rgba(128, 128, 128, 0.4); /* Blur effect from inside */
|
||||
background-color: rgba(128, 128, 128, 0.2); /* Light glow inside */
|
||||
}
|
||||
|
||||
/* Remove hover effects when not hovering */
|
||||
#theme-toggle:not(:hover) #theme-icon {
|
||||
opacity: 0.6; /* Slightly transparent */
|
||||
}
|
||||
7
nextcloud-aio/php/public/timezone.js
Normal file
7
nextcloud-aio/php/public/timezone.js
Normal file
@@ -0,0 +1,7 @@
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// timezone
|
||||
let timezone = document.getElementById("timezone");
|
||||
if (timezone) {
|
||||
timezone.value = Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
}
|
||||
});
|
||||
37
nextcloud-aio/php/public/toggle-dark-mode.js
Normal file
37
nextcloud-aio/php/public/toggle-dark-mode.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// Function to toggle theme
|
||||
function toggleTheme() {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme');
|
||||
const newTheme = (currentTheme === 'dark') ? '' : 'dark'; // Toggle between no theme and dark theme
|
||||
document.documentElement.setAttribute('data-theme', newTheme);
|
||||
localStorage.setItem('theme', newTheme);
|
||||
|
||||
// Change the icon based on the current theme
|
||||
const themeIcon = document.getElementById('theme-icon');
|
||||
themeIcon.textContent = newTheme === 'dark' ? '☀️' : '🌙'; // Switch between moon and sun icons
|
||||
}
|
||||
|
||||
// Function to immediately apply saved theme without icon update
|
||||
function applySavedThemeImmediately() {
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
} else {
|
||||
document.documentElement.removeAttribute('data-theme'); // Default to light theme
|
||||
}
|
||||
}
|
||||
|
||||
// Function to apply theme-icon update
|
||||
function setThemeIcon() {
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
document.getElementById('theme-icon').textContent = '☀️'; // Sun icon for dark mode
|
||||
} else {
|
||||
document.getElementById('theme-icon').textContent = '🌙'; // Moon icon for light mode
|
||||
}
|
||||
}
|
||||
|
||||
// Immediately apply the saved theme to avoid flickering
|
||||
applySavedThemeImmediately();
|
||||
|
||||
// Apply theme when the page loads
|
||||
document.addEventListener('DOMContentLoaded', setThemeIcon);
|
||||
Reference in New Issue
Block a user