Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions src/confighttp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ void getIndexPage(resp_https_t response, req_https_t request) {

std::string header = read_file(WEB_DIR "header.html");
std::string content = read_file(WEB_DIR "index.html");
response->write(header + content);
std::string footer = read_file(WEB_DIR "footer.html");
response->write(header + content + footer);
}

void getPinPage(resp_https_t response, req_https_t request) {
Expand All @@ -163,7 +164,8 @@ void getPinPage(resp_https_t response, req_https_t request) {

std::string header = read_file(WEB_DIR "header.html");
std::string content = read_file(WEB_DIR "pin.html");
response->write(header + content);
std::string footer = read_file(WEB_DIR "footer.html");
response->write(header + content + footer);
}

void getAppsPage(resp_https_t response, req_https_t request) {
Expand All @@ -176,7 +178,8 @@ void getAppsPage(resp_https_t response, req_https_t request) {

std::string header = read_file(WEB_DIR "header.html");
std::string content = read_file(WEB_DIR "apps.html");
response->write(header + content, headers);
std::string footer = read_file(WEB_DIR "footer.html");
response->write(header + content + footer, headers);
}

void getClientsPage(resp_https_t response, req_https_t request) {
Expand All @@ -186,7 +189,8 @@ void getClientsPage(resp_https_t response, req_https_t request) {

std::string header = read_file(WEB_DIR "header.html");
std::string content = read_file(WEB_DIR "clients.html");
response->write(header + content);
std::string footer = read_file(WEB_DIR "footer.html");
response->write(header + content + footer);
}

void getConfigPage(resp_https_t response, req_https_t request) {
Expand All @@ -196,7 +200,8 @@ void getConfigPage(resp_https_t response, req_https_t request) {

std::string header = read_file(WEB_DIR "header.html");
std::string content = read_file(WEB_DIR "config.html");
response->write(header + content);
std::string footer = read_file(WEB_DIR "footer.html");
response->write(header + content + footer + footer);
}

void getPasswordPage(resp_https_t response, req_https_t request) {
Expand All @@ -206,7 +211,8 @@ void getPasswordPage(resp_https_t response, req_https_t request) {

std::string header = read_file(WEB_DIR "header.html");
std::string content = read_file(WEB_DIR "password.html");
response->write(header + content);
std::string footer = read_file(WEB_DIR "footer.html");
response->write(header + content + footer);
}

void getWelcomePage(resp_https_t response, req_https_t request) {
Expand All @@ -217,7 +223,8 @@ void getWelcomePage(resp_https_t response, req_https_t request) {
}
std::string header = read_file(WEB_DIR "header-no-nav.html");
std::string content = read_file(WEB_DIR "welcome.html");
response->write(header + content);
std::string footer = read_file(WEB_DIR "footer.html");
response->write(header + content + footer);
}

void getTroubleshootingPage(resp_https_t response, req_https_t request) {
Expand All @@ -227,7 +234,8 @@ void getTroubleshootingPage(resp_https_t response, req_https_t request) {

std::string header = read_file(WEB_DIR "header.html");
std::string content = read_file(WEB_DIR "troubleshooting.html");
response->write(header + content);
std::string footer = read_file(WEB_DIR "footer.html");
response->write(header + content + footer);
}

void getFaviconImage(resp_https_t response, req_https_t request) {
Expand Down Expand Up @@ -257,24 +265,23 @@ bool isChildPath(fs::path const &base, fs::path const &query) {
return *(relPath.begin()) != fs::path("..");
}

void getNodeModules(resp_https_t response, req_https_t request) {
void getWebAsset(resp_https_t response, req_https_t request) {
print_req(request);
fs::path webDirPath(WEB_DIR);
fs::path nodeModulesPath(webDirPath / "node_modules");
fs::path assetsDirPath(SUNSHINE_ASSETS_DIR);

// .relative_path is needed to shed any leading slash that might exist in the request path
auto filePath = fs::weakly_canonical(webDirPath / fs::path(request->path).relative_path());
auto filePath = fs::weakly_canonical(assetsDirPath / fs::path(request->path).relative_path());

// Don't do anything if file does not exist or is outside the node_modules directory
if(!isChildPath(filePath, nodeModulesPath)) {
BOOST_LOG(warning) << "Someone requested a path " << filePath << " that is outside the node_modules folder";
// Don't do anything if file does not exist or is outside the assets directory
if(!isChildPath(filePath, assetsDirPath)) {
BOOST_LOG(warning) << "Someone requested a path " << filePath << " that is outside the assets directory";
response->write(SimpleWeb::StatusCode::client_error_bad_request, "Bad Request");
}
else if(!fs::exists(filePath)) {
response->write(SimpleWeb::StatusCode::client_error_not_found);
}
else {
auto relPath = fs::relative(filePath, webDirPath);
auto relPath = fs::relative(filePath, assetsDirPath);
// get the mime type from the file extension mime_types map
// remove the leading period from the extension
auto mimeType = mime_types.find(relPath.extension().string().substr(1));
Expand Down Expand Up @@ -729,7 +736,7 @@ void start() {
server.resource["^/api/covers/upload$"]["POST"] = uploadCover;
server.resource["^/images/favicon.ico$"]["GET"] = getFaviconImage;
server.resource["^/images/logo-sunshine-45.png$"]["GET"] = getSunshineLogoImage;
server.resource["^/node_modules\\/.+$"]["GET"] = getNodeModules;
server.resource["^/(web)\\/.+$"]["GET"] = getWebAsset;
server.config.reuse_address = true;
server.config.address = "0.0.0.0"s;
server.config.port = port_https;
Expand Down
24 changes: 24 additions & 0 deletions src_assets/common/assets/web/css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
:root, [data-bs-theme=light]{
--bs-primary-rgb: 255, 196, 0;
}
[data-bs-theme=dark]{
--bs-primary-rgb: 25, 27, 30;
}

#toggleTheme{
margin-left:auto;
margin-right:10px;
}
#toggleTheme span:not(.active){
display:none;
}
@media(min-width:992px){
#toggleTheme{
position:absolute;
right:0;
}
}

html[data-bs-theme="dark"] #toggleTheme i{
color:#fff;
}
9 changes: 9 additions & 0 deletions src_assets/common/assets/web/footer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script src="/web/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://app.lizardbyte.dev/js/discord.js"></script>
<script src="/web/js/main.js"></script>



</body>
</html>
10 changes: 4 additions & 6 deletions src_assets/common/assets/web/header-no-nav.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sunshine</title>
<link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="/node_modules/vue/dist/vue.min.js"></script>
<link href="/web/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="/web/css/main.css" rel="stylesheet" />
<script src="/web/node_modules/vue/dist/vue.min.js"></script>
</head>

<body></body>
</html>
<body>
43 changes: 12 additions & 31 deletions src_assets/common/assets/web/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sunshine</title>
<link rel="icon" type="image/x-icon" href="/images/favicon.ico">
<link href="/node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet">
<link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="/node_modules/vue/dist/vue.min.js"></script>
<link href="/web/node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet">
<link href="/web/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="/web/css/main.css" rel="stylesheet" />
<script src="/web/node_modules/vue/dist/vue.min.js"></script>
</head>

<body>
<nav
class="navbar navbar-expand-lg navbar-light"
style="background-color: #ffc400"
>
<nav class="navbar navbar-expand-lg bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="/" title="Sunshine">
<img src="/images/logo-sunshine-45.png" height="45" alt="Sunshine">
<img src="/web/images/logo-sunshine-45.png" height="45" alt="Sunshine">
</a>
<button class="btn" type="button" id="toggleTheme">
<span data-bs-theme="light"><i class="fas fa-fw fa-sun"></i></span>
<span data-bs-theme="dark"><i class="fas fa-fw fa-moon"></i></span>
<span data-bs-theme="auto" class="active"><i class="fas fa-fw fa-adjust"></i></span>
</button>
<button
class="navbar-toggler"
type="button"
Expand Down Expand Up @@ -56,25 +58,4 @@
</div>
</div>
</nav>
</body>
</html>

<script>
let el = document.querySelector("a[href='"+document.location.pathname+"']");
if(el)el.classList.add("active")
</script>

<style>
.nav-link.active {
font-weight: 500;
}
</style>

<!-- Discord WidgetBot Crate-->
<script src="https://cdn.jsdelivr.net/npm/@widgetbot/crate@3" async defer>
new Crate({
server: '804382334370578482',
channel: '804383092822900797',
defer: false,
})
</script>

79 changes: 79 additions & 0 deletions src_assets/common/assets/web/js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
var sunshineUI = {
init: function() {
sunshineUI.toggleTheme();
//document click events
const btn = document.querySelector("#toggleTheme");
btn.addEventListener("click", function() {
sunshineUI.toggleTheme(1);
});

},
toggleTheme: function(click) {
let themeCookie = getCookie("sunshineTheme");
let options = document.querySelector('#toggleTheme');
let btn = options.querySelector('.active');

if (!click) {
//init page load
if (themeCookie != null) {
//cookie is set, make that button active
btn = options.querySelectorAll('[data-bs-theme="' + themeCookie + '"]')[0];
}
} else {
let optionCount = getChildNodes(btn).count;
let optionIndex = getChildNodes(btn).index;
if (optionIndex < (optionCount - 1)) {
optionIndex++;
} else {
optionIndex = 0;
}
btn = options.children[optionIndex];
}
//set the theme & cookie
let theme = btn.getAttribute('data-bs-theme');
document.cookie = 'sunshineTheme=' + theme + ';';

//remove all active classes from all buttons
options.querySelectorAll('span').forEach((element) => {
element.classList.remove('active');
});


//If it's the auto theme, determine what the computer prefers
if (theme == "auto") {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = "dark";
} else {
theme = "light";
}
}

//apply data attribute to html
document.querySelector('html').setAttribute('data-bs-theme', theme);
let icon = document.querySelector("#toggleTheme .active i");
//icon.className = btn.query.className;
btn.classList.add("active");
}
}

sunshineUI.init();

function getCookie(name) {
let value = `; ${document.cookie}`;
let parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}

function getChildNodes(elm) {
var obj = {
children: elm.parentNode.children,
count: elm.parentNode.children.length
}
var c = obj.count;
while (c--) {
if (obj.children[c] == elm) {
obj.index = (c);
}
}
return obj;
}