diff --git a/public/css/account-server.css b/public/css/account-server.css new file mode 100644 index 0000000..86df667 --- /dev/null +++ b/public/css/account-server.css @@ -0,0 +1,39 @@ +/* --- License +* Version: 1.0 +* File: /public/css/account-server.scss +* Project: account-server +* Created Date: 14 April 2026 +* Copyright (c) 2026 OpenMinerva +* License: MIT License +* Authors: Armored Dragon +* --- License */ +/* --- License +* Version: 1.0 +* File: /public/css/colors.scss +* Project: account-server +* Created Date: 04 March 2026 +* Copyright (c) 2026 OpenMinerva +* License: MIT License +* Authors: Armored Dragon +* --- License */ +body .container .account-container { + width: 100%; + min-height: 40px; + background-color: rgb(229.5, 229.5, 229.5); + border-radius: 10px; + margin-bottom: 1rem; + padding: 1rem; + box-sizing: border-box; + display: flex; + flex-direction: row; +} +body .container .account-header .account-picture { + aspect-ratio: 1/1; + height: 150px; + background-color: #cccccc; + margin-right: 1rem; + border-radius: 10px; +} +body .container .account-header .account-info .account-info-name { + font-size: 1.5rem; +} diff --git a/public/css/account-server.scss b/public/css/account-server.scss new file mode 100644 index 0000000..5644bc0 --- /dev/null +++ b/public/css/account-server.scss @@ -0,0 +1,46 @@ +/* --- License +* Version: 1.0 +* File: /public/css/account-server.scss +* Project: account-server +* Created Date: 14 April 2026 +* Copyright (c) 2026 OpenMinerva +* License: MIT License +* Authors: Armored Dragon +* --- License */ + +@use "colors"; + +body { + .container { + .account-container { + width: 100%; + min-height: 40px; + background-color: colors.$om-gray1; + border-radius: 10px; + margin-bottom: 1rem; + padding: 1rem; + box-sizing: border-box; + display: flex; + flex-direction: row; + } + .account-header { + .account-picture { + aspect-ratio: 1/1; + height: 150px; + + background-color: colors.$om-gray2; + margin-right: 1rem; + border-radius: 10px; + } + + .account-info { + .account-info-name { + font-size: 1.5rem; + } + } + } + + .account-biography { + } + } +} diff --git a/public/css/colors.css b/public/css/colors.css index e69de29..78a33b8 100644 --- a/public/css/colors.css +++ b/public/css/colors.css @@ -0,0 +1,9 @@ +/* --- License +* Version: 1.0 +* File: /public/css/colors.scss +* Project: account-server +* Created Date: 04 March 2026 +* Copyright (c) 2026 OpenMinerva +* License: MIT License +* Authors: Armored Dragon +* --- License */ diff --git a/public/css/colors.scss b/public/css/colors.scss index 3077dc7..3e8c339 100644 --- a/public/css/colors.scss +++ b/public/css/colors.scss @@ -1,9 +1,35 @@ -$bg-1: #2e3132; -$bg-2: #4b4f53; +/* --- License +* Version: 1.0 +* File: /public/css/colors.scss +* Project: account-server +* Created Date: 04 March 2026 +* Copyright (c) 2026 OpenMinerva +* License: MIT License +* Authors: Armored Dragon +* --- License */ -$bg-button: #445c75; -$bg-button-hover: #2d3c4d; -$bg-button-disabled: #313840; +$om-gray1: darken(white, 10%); +$om-gray2: darken(white, 20%); +$om-gray3: darken(white, 30%); +$om-gray4: darken(white, 40%); +$om-gray5: darken(white, 50%); +$om-gray6: darken(white, 60%); +$om-gray7: darken(white, 70%); +$om-gray8: darken(white, 80%); +$om-gray9: darken(white, 90%); -$text-color: white; -$dull-text-color: rgb(200, 200, 200); \ No newline at end of file +$om-blue1: #0077ff; +$om-blue2: darken(#0077ff, 20%); +$om-blue3: darken(#0077ff, 30%); +$om-blue4: darken(#0077ff, 40%); +$om-blue5: darken(#0077ff, 50%); + +$om-red1: darken(#ff1e00, 10%); +$om-red2: darken(#ff1e00, 20%); +$om-red3: darken(#ff1e00, 30%); +$om-red4: darken(#ff1e00, 40%); +$om-red5: darken(#ff1e00, 50%); +$om-red6: darken(#ff1e00, 60%); +$om-red7: darken(#ff1e00, 70%); +$om-red8: darken(#ff1e00, 80%); +$om-red9: darken(#ff1e00, 90%); diff --git a/public/css/generic.css b/public/css/generic.css deleted file mode 100644 index ebcb05d..0000000 --- a/public/css/generic.css +++ /dev/null @@ -1,190 +0,0 @@ -body { - display: flex; - flex-direction: column; - margin: 0; - background-color: #2e3132; - height: 100vh; - width: 100vw; - font-family: Verdana, Geneva, Tahoma, sans-serif; -} -body .login-container { - background-color: #4b4f53; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - color: white; - font-family: Verdana, Geneva, Tahoma, sans-serif; - text-align: center; - width: 450px; - margin: auto; - padding: 1rem; - box-sizing: border-box; -} -body .login-container .logo { - height: 50px; - margin-bottom: 1rem; - display: flex; - flex-direction: row; -} -body .login-container .logo img { - height: 100%; - width: auto; -} -body .login-container .logo div { - margin: auto auto auto 1rem; - font-size: 2rem; -} -body .text-entry { - width: 100%; - padding: 0.25rem; - box-sizing: border-box; - margin-bottom: 1rem; -} -body .text-entry .title { - text-align: left; -} -body .text-entry input { - height: 30px; - width: 100%; - box-sizing: border-box; -} -body .text-entry.last { - margin-bottom: 0; -} -body .button-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - width: 100%; - margin-top: 1rem; -} -body .button-container button { - width: 100%; - background-color: #445c75; - color: white; - border: none; - border-radius: 4px; - padding: 0.5rem 1rem; - cursor: pointer; - transition: background-color 0.3s ease; - margin-right: 1rem; -} -body .button-container button:hover { - background-color: #2d3c4d; -} -body .button-container button:last-of-type { - margin-right: 0; -} -body .navbar { - display: flex; - flex-direction: row; - width: 100%; - height: 50px; - background-color: #4b4f53; -} -body .navbar .logo { - height: 100%; - padding: 0.5rem; - box-sizing: border-box; -} -body .navbar .logo a { - height: 100%; - display: flex; - flex-direction: row; - text-decoration: none; - color: white; -} -body .navbar .logo a img { - height: 100%; -} -body .navbar .logo a span { - margin: auto auto auto 1rem; - font-size: 2rem; - font-family: Verdana, Geneva, Tahoma, sans-serif; -} -body .navbar .nav { - margin: auto 0 auto auto; - height: 100%; - display: flex; - flex-direction: row; -} -body .navbar .nav a { - height: 100%; - width: 100px; - background-color: #445c75; - display: flex; - flex-direction: row; - text-decoration: none; - color: white; -} -body .navbar .nav a span { - margin: auto; -} -body .navbar .nav a:hover { - background-color: #2d3c4d; -} -body .page-content { - width: 1200px; - margin: 2rem auto; - background-color: #4b4f53; - padding: 1rem; - box-sizing: border-box; - color: white; -} - -.hidden { - display: none !important; -} - -button { - display: flex; - flex-direction: row; - background-color: #445c75; - text-decoration: none; - border: 0; - cursor: pointer; -} -button span { - margin: auto; - color: white; -} -button:hover { - background-color: #2d3c4d; -} - -dialog { - background-color: #4b4f53; - color: white; - border: 0; - width: 500px; -} -dialog::backdrop { - background-color: rgba(0, 0, 0, 0.75); -} -dialog .dialog-title { - font-size: 1.3rem; - text-align: center; - margin-bottom: 1rem; -} -dialog .dialog-entry { - margin-bottom: 1rem; - display: flex; - width: 100%; -} -dialog .dialog-entry input { - width: 100%; - height: 26px; - padding: 0; - margin: 0; -} -dialog .horizontal-button { - display: flex; - flex-direction: row; - gap: 1rem; -} -dialog .horizontal-button button { - width: 100%; - height: 30px; -} \ No newline at end of file diff --git a/public/css/generic.scss b/public/css/generic.scss deleted file mode 100644 index d2c53ea..0000000 --- a/public/css/generic.scss +++ /dev/null @@ -1,225 +0,0 @@ -@use "colors"; - -body { - display: flex; - flex-direction: column; - margin: 0; - background-color: colors.$bg-1; - height: 100vh; - width: 100vw; - font-family: Verdana, Geneva, Tahoma, sans-serif; - - .login-container { - background-color: colors.$bg-2; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - color: colors.$text-color; - font-family: Verdana, Geneva, Tahoma, sans-serif; - text-align: center; - width: 450px; - margin: auto; - padding: 1rem; - box-sizing: border-box; - - .logo { - height: 50px; - margin-bottom: 1rem; - display: flex; - flex-direction: row; - - img { - height: 100%; - width: auto; - } - - div { - margin: auto auto auto 1rem; - font-size: 2rem; - } - } - } - - .text-entry { - width: 100%; - padding: 0.25rem; - box-sizing: border-box; - margin-bottom: 1rem; - - .title { - text-align: left; - } - - input { - height: 30px; - width: 100%; - box-sizing: border-box; - } - } - - .text-entry.last { - margin-bottom: 0; - } - - .button-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - width: 100%; - margin-top: 1rem; - - button { - width: 100%; - background-color: colors.$bg-button; - color: colors.$text-color; - border: none; - border-radius: 4px; - padding: 0.5rem 1rem; - cursor: pointer; - transition: background-color 0.3s ease; - margin-right: 1rem; - - &:hover { - background-color: colors.$bg-button-hover; - } - } - - button:last-of-type { - margin-right: 0; - } - } - - .navbar { - display: flex; - flex-direction: row; - width: 100%; - height: 50px; - background-color: colors.$bg-2; - - .logo { - height: 100%; - padding: 0.5rem; - box-sizing: border-box; - - a { - height: 100%; - display: flex; - flex-direction: row; - text-decoration: none; - color: white; - - img { - height: 100%; - } - - span { - margin: auto auto auto 1rem; - font-size: 2rem; - font-family: Verdana, Geneva, Tahoma, sans-serif; - } - } - - } - - .nav { - margin: auto 0 auto auto; - height: 100%; - display: flex; - flex-direction: row; - - a { - height: 100%; - width: 100px; - background-color: colors.$bg-button; - display: flex; - flex-direction: row; - text-decoration: none; - color: white; - - span { - margin: auto; - } - - &:hover { - background-color: colors.$bg-button-hover; - } - } - - } - } - - .page-content { - width: 1200px; - margin: 2rem auto; - background-color: colors.$bg-2; - padding: 1rem; - box-sizing: border-box; - color: white; - } -} - -.hidden { - display: none !important; -} - -button { - display: flex; - flex-direction: row; - background-color: colors.$bg-button; - text-decoration: none; - border: 0; - - cursor: pointer; - - span { - margin: auto; - color: white; - } - - &:hover { - background-color: colors.$bg-button-hover; - } -} - -dialog { - background-color: colors.$bg-2; - color: white; - border: 0; - width: 500px; - - &::backdrop { - background-color: rgba(0, 0, 0, 0.75); - } - - .dialog-title { - font-size: 1.3rem; - text-align: center; - margin-bottom: 1rem; - } - - .dialog-entry { - margin-bottom: 1rem; - display: flex; - width: 100%; - - input { - width: 100%; - height: 26px; - padding: 0; - margin: 0; - } - } - - .horizontal-button { - display: flex; - flex-direction: row; - gap: 1rem; - - button { - width: 100%; - height: 30px; - } - } -} \ No newline at end of file diff --git a/public/css/index.css b/public/css/index.css deleted file mode 100644 index e69de29..0000000 diff --git a/public/css/index.scss b/public/css/index.scss deleted file mode 100644 index e69de29..0000000 diff --git a/public/css/profile.css b/public/css/profile.css deleted file mode 100644 index 0696745..0000000 --- a/public/css/profile.css +++ /dev/null @@ -1,23 +0,0 @@ -.page-content .profile-head { - width: 100%; - height: 200px; - display: flex; - flex-direction: row; - margin-bottom: 2rem; -} -.page-content .profile-head .profile-picture-container { - width: 200px; - height: 200px; - background-color: black; - margin-right: 1rem; -} -.page-content .profile-head .profile-badge { - display: flex; - flex-direction: column; -} -.page-content .profile-head .profile-badge .profile-username { - font-size: 2rem; -} -.page-content .profile-body .profile-biography { - font-size: 1.15rem; -} \ No newline at end of file diff --git a/public/css/profile.scss b/public/css/profile.scss deleted file mode 100644 index 901e0d3..0000000 --- a/public/css/profile.scss +++ /dev/null @@ -1,33 +0,0 @@ -.page-content { - .profile-head { - width: 100%; - height: 200px; - display: flex; - flex-direction: row; - margin-bottom: 2rem; - - .profile-picture-container { - width: 200px; - height: 200px; - background-color: black; - margin-right: 1rem; - } - - .profile-badge { - display: flex; - flex-direction: column; - - .profile-username { - font-size: 2rem; - } - } - - .profile-actions {} - } - - .profile-body { - .profile-biography { - font-size: 1.15rem; - } - } -} \ No newline at end of file diff --git a/public/css/profileSettings.css b/public/css/profileSettings.css deleted file mode 100644 index 89c6626..0000000 --- a/public/css/profileSettings.css +++ /dev/null @@ -1,23 +0,0 @@ -.devices-tables { - width: 100%; -} -.devices-tables .min-width { - width: -moz-fit-content; - width: fit-content; -} -.devices-tables .fit-width { - width: -moz-max-content; - width: max-content; -} -.devices-tables .fill-width { - width: 100%; -} -.devices-tables tbody tr td div { - display: flex; - flex-direction: row; - gap: 1rem; -} -.devices-tables tbody tr td div button { - padding: 0.25rem 0.5rem; - box-sizing: border-box; -} \ No newline at end of file diff --git a/public/css/profileSettings.scss b/public/css/profileSettings.scss deleted file mode 100644 index 14e36d4..0000000 --- a/public/css/profileSettings.scss +++ /dev/null @@ -1,32 +0,0 @@ -.devices-tables { - width: 100%; - - .min-width { - width: fit-content; - } - - .fit-width { - width: max-content; - } - - .fill-width { - width: 100%; - } - - tbody { - tr { - td { - div { - display: flex; - flex-direction: row; - gap: 1rem; - - button { - padding: 0.25rem 0.5rem; - box-sizing: border-box; - } - } - } - } - } -} \ No newline at end of file diff --git a/public/css/theme.css b/public/css/theme.css new file mode 100644 index 0000000..78a6332 --- /dev/null +++ b/public/css/theme.css @@ -0,0 +1,447 @@ +/* --- License +* Version: 1.0 +* File: /public/css/theme.scss +* Project: account-server +* Created Date: 14 April 2026 +* Copyright (c) 2026 OpenMinerva +* License: MIT License +* Authors: Armored Dragon +* --- License */ +/* --- License +* Version: 1.0 +* File: /public/css/colors.scss +* Project: account-server +* Created Date: 04 March 2026 +* Copyright (c) 2026 OpenMinerva +* License: MIT License +* Authors: Armored Dragon +* --- License */ +body { + margin: 0; + display: flex; + flex-direction: column; + width: 100vw; + height: 100vh; + font-family: Verdana, Geneva, Tahoma, sans-serif; +} +body nav { + display: flex; + flex-direction: row; + color: white; + background-color: #333333; + min-height: 50px; + height: 50px; + padding: 0 1rem; + box-sizing: border-box; +} +body nav .logo { + display: flex; + color: white; + text-decoration: none; + padding: 0.5rem 0.1rem; + box-sizing: border-box; + margin: auto auto auto 0; + font-size: 1.4rem; + font-weight: bold; + height: 100%; +} +body nav .logo img { + height: 100%; + margin-right: 1rem; +} +body nav .links { + display: flex; + flex-direction: row; + height: 100%; +} +body nav .links a { + color: white; + text-decoration: none; + height: 100%; + min-width: 5rem; + background-color: #333333; + margin: auto; + display: flex; + transition: background-color ease-in-out 0.05s; +} +body nav .links a:hover { + background-color: rgb(25.5, 25.5, 25.5); +} +body nav .links a span { + margin: auto; +} +body .hero { + width: 100%; + min-height: 300px; + height: 300px; + background: linear-gradient(-90deg, #0077ff, rgb(0, 47.6, 102)); + color: white; + display: flex; + flex-direction: column; + border-bottom: 1.5rem solid #333333; +} +body .hero .hero-title { + margin: auto auto 0 auto; + font-size: 3rem; + box-sizing: border-box; + font-weight: bolder; +} +body .hero .hero-subtitle { + margin: 0 auto auto auto; + font-size: 1rem; + box-sizing: border-box; + font-weight: bold; + color: rgb(229.5, 229.5, 229.5); + cursor: help; +} +body .container { + width: 1200px; + margin: 1rem auto 0 auto; +} +body .container .side-by-side { + display: flex; + flex-direction: row; +} +body .container .grid { + display: grid; + gap: 1rem; + margin-top: 1rem; +} +body .container .grid.grid-3 { + grid-template-columns: repeat(3, 1fr); +} +body .container .grid.grid-4 { + grid-template-columns: repeat(4, 1fr); +} +body .container .grid.grid-5 { + grid-template-columns: repeat(5, 1fr); +} +body .container .search { + display: flex; + flex-direction: row; + width: 100%; +} +body .container .search input[type=text] { + width: 100%; + margin-right: 1rem; +} +body .container .panel { + width: 100%; + min-height: 10rem; + background-color: rgb(229.5, 229.5, 229.5); + border-radius: 20px; + margin: auto; +} +body .container .panel.login { + padding: 2rem; + width: 30rem; + box-sizing: border-box; + display: flex; + flex-direction: column; +} +body .container .panel.login .input-area { + margin: auto auto 0 auto; + display: flex; + flex-direction: column; + margin-bottom: 1rem; + width: 100%; +} +body .admin-container { + width: 100%; + height: 100%; + display: flex; + flex-direction: row; +} +body .admin-container .admin-nav { + width: 15rem; + height: 100%; + background-color: rgb(76.5, 76.5, 76.5); +} +body .admin-container .admin-nav .admin-nav-button { + color: white; + display: flex; + flex-direction: row; + height: 3rem; + text-decoration: none; + transition: background-color ease-in-out 0.05s; +} +body .admin-container .admin-nav .admin-nav-button .btn-text { + margin: auto; +} +body .admin-container .admin-nav .admin-nav-button:hover { + background-color: #333333; +} +body .admin-container .admin-content { + width: 700px; + margin: 0 auto; +} +body .admin-container .admin-content .admin-page { + color: black; + margin-top: 2rem; +} +body .admin-container .admin-content .admin-page .admin-page-header { + font-size: 2rem; + text-align: center; +} +body .admin-container .admin-content .admin-page .settings-container { + display: flex; + flex-direction: column; + margin-top: 1rem; + gap: 0.5rem; +} +body .admin-container .admin-content .admin-page .settings-container .setting { + background-color: rgb(229.5, 229.5, 229.5); + display: flex; + flex-direction: row; + padding: 0.5rem; + box-sizing: border-box; + border-radius: 5px; +} +body .admin-container .admin-content .admin-page .settings-container .setting .label { + margin: auto auto auto 0; +} +body .admin-container .admin-content .admin-page .settings-container .setting .interact input[type=checkbox] { + width: 20px; + height: 20px; + cursor: pointer; +} +body .admin-container .admin-content .admin-settings-save-container { + display: flex; + flex-direction: row; + margin-top: 1rem; + width: 100%; +} +body .admin-container .admin-content .admin-settings-save-container .button { + width: 100%; +} +body .spacing-container { + gap: 0.25rem; + display: flex; +} +body footer { + margin: auto 0 0 0; + min-height: 50px; + background-color: #333333; + display: flex; +} +body footer .center { + margin: auto; +} +body footer .center a { + color: white; + transition: color ease-in-out 0.1s; +} +body footer .center a:hover { + color: rgb(178.5, 178.5, 178.5); +} +body dialog { + border-radius: 20px; + width: 500px; + border: 0; +} +body dialog::backdrop { + background: rgba(0, 0, 0, 0.8); +} +body dialog .dialog-content .add-entry { + width: 100%; + display: flex; + flex-direction: row; + margin-bottom: 1rem; + gap: 1rem; +} +body dialog .dialog-content .add-entry input { + width: 100%; +} +body dialog .dialog-content .add-entry .button { + aspect-ratio: 1/1; + width: initial; +} +body dialog .dialog-content .table-container { + max-height: 500px; + overflow-y: auto; +} +body dialog .dialog-content .table-container table { + width: 100%; + border: 0; + border-collapse: collapse; +} +body dialog .dialog-content .table-container table thead { + position: sticky; + top: 0; +} +body dialog .dialog-content .table-container table thead tr { + border: 0; +} +body dialog .dialog-content .table-container table thead tr th { + border: 0; + background-color: #cccccc; + width: 100%; +} +body dialog .dialog-content .table-container table thead tr .shrink { + width: min-content; + padding: 0 1rem 0 0; + box-sizing: border-box; +} +body dialog .dialog-content .table-container table tbody tr:nth-child(even) { + background-color: rgb(229.5, 229.5, 229.5); +} +body dialog .dialog-content .table-container table tbody tr:hover { + background-color: rgb(178.5, 178.5, 178.5); +} +body dialog .dialog-content .table-container table tbody tr td { + border: 0; + padding: 0 0 0 1rem; + box-sizing: border-box; +} +body dialog .dialog-content .table-container table tbody tr td.actions { + display: flex; + flex-direction: row; + padding: 0.2rem; + box-sizing: border-box; +} +body dialog .dialog-content .table-container table tbody tr td.actions a { + margin: auto; +} +body dialog .dialog-content .table-container table tbody tr td.actions .button-trash { + background-color: #cc1800; + aspect-ratio: 1/1; + width: initial; +} +body dialog .dialog-content .table-container table tbody tr td.actions .button-trash:hover { + background-color: #660c00; +} +body dialog .admin-settings-save-container { + display: flex; + flex-direction: row; + margin-top: 1rem; + width: 100%; + gap: 1rem; +} +body dialog .admin-settings-save-container .button { + width: 100%; +} +body dialog .admin-settings-save-container .button.dull { + background-color: rgb(229.5, 229.5, 229.5); + color: black; +} +body dialog .admin-settings-save-container .button.dull:hover { + background-color: rgb(178.5, 178.5, 178.5); +} + +.btn-container { + width: 100%; + display: flex; + flex-direction: row; + gap: 1rem; + margin-top: 1rem; +} +.btn-container button, +.btn-container .btn { + width: 100%; +} + +.btn { + padding: 0 1rem; + box-sizing: border-box; + background-color: #0077ff; + transition: background-color ease-in-out 0.05s; + border-radius: 10px; + color: white; + cursor: pointer; + text-decoration: none; + width: 10rem; + height: 35px; + display: flex; + border: 0; +} +.btn .btn-icon-container { + height: 100%; + display: flex; + margin: auto; +} +.btn .btn-icon-container img { + height: 100%; + padding: 0.2rem; + box-sizing: border-box; + margin: auto; +} +.btn .btn-text { + font-size: 1rem; + font-weight: normal; + text-decoration: none; + user-select: none; + text-align: center; + margin: auto; +} +.btn:hover { + background-color: rgb(0, 71.4, 153); +} +.btn.btn-icon-only { + width: 4rem; +} + +.btn.btn-red { + background-color: #cc1800; +} +.btn.btn-red:hover { + background-color: #991200; +} + +.btn.btn-gray { + background-color: #666666; +} +.btn.btn-gray:hover { + background-color: #333333; +} + +.drop-multiselect, +.drop-select { + display: flex; + position: relative; +} +.drop-multiselect .drop-menu, +.drop-select .drop-menu { + display: none; + border: 1px solid #ccc; + background-color: white; + padding: 5px; + position: absolute; + color: black; + width: max-content; + border-radius: 10px; + z-index: 2; + top: 0; +} +.drop-multiselect .drop-menu label, +.drop-select .drop-menu label { + padding: 0.25rem; + box-sizing: border-box; +} +.drop-multiselect input[type=checkbox]:checked ~ .drop-menu, +.drop-select input[type=checkbox]:checked ~ .drop-menu { + display: flex; + flex-direction: column; + top: 100%; +} +.drop-multiselect input[type=checkbox]:checked + .button, +.drop-select input[type=checkbox]:checked + .button { + background-color: rgb(0, 47.6, 102); +} + +input[type=text], +input[type=password] { + border: 1px solid #333333; + border-radius: 10px; + color: black; + padding: 0.05rem 0.5rem; + font-size: 1.1rem; +} + +@media screen and (max-width: 1210px) { + body .container { + width: 95%; + } +} +.hidden { + display: none !important; +} diff --git a/public/css/theme.scss b/public/css/theme.scss new file mode 100644 index 0000000..beb1234 --- /dev/null +++ b/public/css/theme.scss @@ -0,0 +1,533 @@ +/* --- License +* Version: 1.0 +* File: /public/css/theme.scss +* Project: account-server +* Created Date: 14 April 2026 +* Copyright (c) 2026 OpenMinerva +* License: MIT License +* Authors: Armored Dragon +* --- License */ +@use "colors"; + +body { + margin: 0; + display: flex; + flex-direction: column; + width: 100vw; + height: 100vh; + font-family: Verdana, Geneva, Tahoma, sans-serif; + + nav { + display: flex; + flex-direction: row; + color: white; + background-color: colors.$om-gray8; + min-height: 50px; + height: 50px; + padding: 0 1rem; + box-sizing: border-box; + + .logo { + display: flex; + color: white; + text-decoration: none; + padding: 0.5rem 0.1rem; + box-sizing: border-box; + margin: auto auto auto 0; + font-size: 1.4rem; + font-weight: bold; + height: 100%; + + img { + height: 100%; + margin-right: 1rem; + } + } + + .links { + display: flex; + flex-direction: row; + height: 100%; + + a { + color: white; + text-decoration: none; + height: 100%; + min-width: 5rem; + background-color: colors.$om-gray8; + margin: auto; + display: flex; + transition: background-color ease-in-out 0.05s; + + &:hover { + background-color: colors.$om-gray9; + } + + span { + margin: auto; + } + } + } + } + + .hero { + width: 100%; + min-height: 300px; + height: 300px; + background: linear-gradient(-90deg, colors.$om-blue1, colors.$om-blue3); + color: white; + display: flex; + flex-direction: column; + border-bottom: 1.5rem solid colors.$om-gray8; + + .hero-title { + margin: auto auto 0 auto; + font-size: 3rem; + box-sizing: border-box; + font-weight: bolder; + } + + .hero-subtitle { + margin: 0 auto auto auto; + font-size: 1rem; + box-sizing: border-box; + font-weight: bold; + color: colors.$om-gray1; + cursor: help; + } + } + + .container { + width: 1200px; + margin: 1rem auto 0 auto; + + .side-by-side { + display: flex; + flex-direction: row; + } + + .flow-grid { + } + + .grid { + display: grid; + gap: 1rem; + margin-top: 1rem; + + &.grid-3 { + grid-template-columns: repeat(3, 1fr); + } + + &.grid-4 { + grid-template-columns: repeat(4, 1fr); + } + + &.grid-5 { + grid-template-columns: repeat(5, 1fr); + } + } + + .search { + display: flex; + flex-direction: row; + width: 100%; + + input[type="text"] { + width: 100%; + margin-right: 1rem; + } + } + + .panel { + width: 100%; + min-height: 10rem; + background-color: colors.$om-gray1; + border-radius: 20px; + margin: auto; + + &.login { + padding: 2rem; + width: 30rem; + box-sizing: border-box; + display: flex; + flex-direction: column; + + .input-area { + margin: auto auto 0 auto; + display: flex; + flex-direction: column; + margin-bottom: 1rem; + width: 100%; + } + } + } + } + + .admin-container { + width: 100%; + height: 100%; + display: flex; + flex-direction: row; + + .admin-nav { + width: 15rem; + height: 100%; + background-color: colors.$om-gray7; + + .admin-nav-button { + color: white; + display: flex; + flex-direction: row; + height: 3rem; + text-decoration: none; + transition: background-color ease-in-out 0.05s; + + .btn-text { + margin: auto; + } + + &:hover { + background-color: colors.$om-gray8; + } + } + } + + .admin-content { + width: 700px; + margin: 0 auto; + + .admin-page { + color: black; + margin-top: 2rem; + + .admin-page-header { + font-size: 2rem; + text-align: center; + } + + .settings-container { + display: flex; + flex-direction: column; + margin-top: 1rem; + gap: 0.5rem; + + .setting { + background-color: colors.$om-gray1; + display: flex; + flex-direction: row; + padding: 0.5rem; + box-sizing: border-box; + border-radius: 5px; + + .label { + margin: auto auto auto 0; + } + + .interact { + input[type="checkbox"] { + width: 20px; + height: 20px; + cursor: pointer; + } + } + } + } + } + + .admin-settings-save-container { + display: flex; + flex-direction: row; + margin-top: 1rem; + width: 100%; + + .button { + width: 100%; + } + } + } + } + + .spacing-container { + gap: 0.25rem; + display: flex; + } + + footer { + margin: auto 0 0 0; + min-height: 50px; + background-color: colors.$om-gray8; + display: flex; + + .center { + margin: auto; + + a { + color: white; + transition: color ease-in-out 0.1s; + + &:hover { + color: darken(white, 30%); + } + } + } + } + + dialog { + border-radius: 20px; + width: 500px; + border: 0; + + &::backdrop { + background: #000000cc; + } + + .dialog-content { + .add-entry { + width: 100%; + display: flex; + flex-direction: row; + margin-bottom: 1rem; + gap: 1rem; + + input { + width: 100%; + } + + .button { + aspect-ratio: 1/1; + width: initial; + } + } + + .table-container { + max-height: 500px; + overflow-y: auto; + + table { + width: 100%; + border: 0; + border-collapse: collapse; + + thead { + position: sticky; + top: 0; + + tr { + border: 0; + + th { + border: 0; + background-color: colors.$om-gray2; + width: 100%; + } + + .shrink { + width: min-content; + padding: 0 1rem 0 0; + box-sizing: border-box; + } + } + } + + tbody { + tr { + &:nth-child(even) { + background-color: colors.$om-gray1; + } + + &:hover { + background-color: colors.$om-gray3; + } + + td { + border: 0; + padding: 0 0 0 1rem; + box-sizing: border-box; + + &.actions { + display: flex; + flex-direction: row; + padding: 0.2rem; + box-sizing: border-box; + + a { + margin: auto; + } + + .button-trash { + background-color: colors.$om-red1; + aspect-ratio: 1/1; + width: initial; + + &:hover { + background-color: colors.$om-red3; + } + } + } + } + } + } + } + } + } + + .admin-settings-save-container { + display: flex; + flex-direction: row; + margin-top: 1rem; + width: 100%; + gap: 1rem; + + .button { + width: 100%; + } + + .button.dull { + background-color: colors.$om-gray1; + color: black; + + &:hover { + background-color: colors.$om-gray3; + } + } + } + } +} + +// Defaults +.btn-container { + width: 100%; + display: flex; + flex-direction: row; + gap: 1rem; + margin-top: 1rem; + + button, + .btn { + width: 100%; + } +} + +.btn { + padding: 0 1rem; + box-sizing: border-box; + background-color: colors.$om-blue1; + transition: background-color ease-in-out 0.05s; + border-radius: 10px; + color: white; + cursor: pointer; + text-decoration: none; + width: 10rem; + height: 35px; + display: flex; + border: 0; + + .btn-icon-container { + height: 100%; + display: flex; + margin: auto; + + img { + height: 100%; + padding: 0.2rem; + box-sizing: border-box; + margin: auto; + } + } + + .btn-text { + font-size: 1rem; + font-weight: normal; + text-decoration: none; + user-select: none; + text-align: center; + margin: auto; + } + + &:hover { + background-color: colors.$om-blue2; + } + + &.btn-icon-only { + width: 4rem; + } +} + +.btn.btn-red { + background-color: colors.$om-red1; + + &:hover { + background-color: colors.$om-red2; + } +} + +.btn.btn-gray { + background-color: colors.$om-gray6; + + &:hover { + background-color: colors.$om-gray8; + } +} + +.drop-select { +} + +.drop-multiselect { +} + +.drop-multiselect, +.drop-select { + display: flex; + position: relative; + + .drop-menu { + display: none; + border: 1px solid #ccc; + background-color: white; + padding: 5px; + position: absolute; + color: black; + width: max-content; + border-radius: 10px; + z-index: 2; + top: 0; + + label { + padding: 0.25rem; + box-sizing: border-box; + } + } + + input[type="checkbox"]:checked ~ .drop-menu { + display: flex; + flex-direction: column; + top: 100%; + } + + input[type="checkbox"]:checked + .button { + background-color: colors.$om-blue3; + } +} + +input[type="text"], +input[type="password"] { + border: 1px solid colors.$om-gray8; + border-radius: 10px; + color: black; + padding: 0.05rem 0.5rem; + font-size: 1.1rem; +} + +// Scaling +@media screen and (max-width: 1210px) { + body { + .container { + width: 95%; + } + } +} + +// Overrides +.hidden { + display: none !important; +} diff --git a/public/img/1280x720_dummy.webp b/public/img/1280x720_dummy.webp new file mode 100644 index 0000000..b50f87f Binary files /dev/null and b/public/img/1280x720_dummy.webp differ diff --git a/public/img/icons/add.svg b/public/img/icons/add.svg new file mode 100644 index 0000000..1d78852 --- /dev/null +++ b/public/img/icons/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/icons/trash.svg b/public/img/icons/trash.svg new file mode 100644 index 0000000..714432c --- /dev/null +++ b/public/img/icons/trash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/logoSmall.webp b/public/img/logoSmall.webp index 92c1c2c..8f505fe 100644 Binary files a/public/img/logoSmall.webp and b/public/img/logoSmall.webp differ diff --git a/public/img/logos/om-logo-big.webp b/public/img/logos/om-logo-big.webp new file mode 100644 index 0000000..04fe460 Binary files /dev/null and b/public/img/logos/om-logo-big.webp differ diff --git a/public/img/logos/om-logo.svg b/public/img/logos/om-logo.svg new file mode 100644 index 0000000..00edb2b --- /dev/null +++ b/public/img/logos/om-logo.svg @@ -0,0 +1,104 @@ + + + + diff --git a/public/img/search.svg b/public/img/search.svg new file mode 100644 index 0000000..27affe0 --- /dev/null +++ b/public/img/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app.js b/src/app.js index 74e92a2..d2e95a2 100644 --- a/src/app.js +++ b/src/app.js @@ -23,7 +23,7 @@ const fs = require("fs"); // Routes const indexRoutes = require("./routes/index"); const accountRoutes = require("./routes/account"); -// const adminRoutes = require("./routes/admin"); +const adminRoutes = require("./routes/admin"); const apiRoutes = require("./routes/api"); const oauthRoutes = require("./routes/oauth"); @@ -152,7 +152,7 @@ async function createApp() { app.use("/api", apiRoutes); app.use(ensureSetup.middleware); app.use("/account", accountRoutes); - // app.use("/admin", adminRoutes); + app.use("/admin", adminRoutes); app.use("/", indexRoutes); app.use("/oauth", oauthRoutes); app.use("/oauth", oidc.callback()); diff --git a/src/controllers/account.js b/src/controllers/account.js index ae83dbe..e6a1ab3 100644 --- a/src/controllers/account.js +++ b/src/controllers/account.js @@ -1,64 +1,73 @@ -const accountService = require('../services/account'); +/* --- License + * File: /src/controllers/account.js + * Project: account-server + * Created Date: 21 January 2026 + * Copyright (c) 2026 OpenMinerva + * License: MIT License + * Authors: Armored Dragon + * --- License */ + +const accountService = require("../services/account"); const getAccount = async (req, res, next) => { - try { - const dbResponse = await accountService.getAccount({ id: req.params.account_id }); + try { + const dbResponse = await accountService.getAccount({ id: req.params.account_id }); - if (!dbResponse) { - // User not found - res.status(404).redirect('/'); - return; - } + if (!dbResponse) { + // User not found + res.status(404).redirect("/"); + return; + } - if (dbResponse.ok == false) { - res.status(200).json(dbResponse); - return; - } + if (dbResponse.ok == false) { + res.status(200).json(dbResponse); + return; + } - res.render("accountSingle", { requestingUser: req.requestingUser, targetUser: dbResponse }); - } catch (err) { - next(err); - } + res.render("accountSingle", { requestingUser: req.requestingUser, targetUser: dbResponse }); + } catch (err) { + next(err); + } }; const getAccountSettings = async (req, res, next) => { - try { - if (_isRequestAllowedToViewPage(req) == false) { - res.status(403).redirect('/'); - return; - } + try { + if (_isRequestAllowedToViewPage(req) == false) { + res.status(403).redirect("/"); + return; + } - const dbResponseAccount = await accountService.getAccount({ id: req.params.account_id }); + const dbResponseAccount = await accountService.getAccount({ id: req.params.account_id }); - if (!dbResponseAccount) { - // User not found - res.status(404).redirect('/'); - return; - } + if (!dbResponseAccount) { + // User not found + res.status(404).redirect("/"); + return; + } - if (dbResponseAccount.ok == false) { - res.status(200).json(dbResponseAccount); - return; - } + if (dbResponseAccount.ok == false) { + res.status(200).json(dbResponseAccount); + return; + } - res.render("accountSettings", { requestingUser: req.requestingUser, targetUser: dbResponseAccount }); - } catch (err) { - next(err); - } + res.render("accountSettings", { requestingUser: req.requestingUser, targetUser: dbResponseAccount }); + } catch (err) { + next(err); + } }; function _isRequestAllowedToViewPage(req) { - if (req.requestingUser == req.params.account_id) { - // Target page is of the user who is logged in - return true - } + if (req.requestingUser == req.params.account_id) { + // Target page is of the user who is logged in + return true; + } - if (req.requestingUser.role == "admin") { - // Admins can see all - return true - } + if (req.requestingUser.role == "admin") { + // Admins can see all + return true; + } - return false + return false; } module.exports = { getAccount, getAccountSettings }; diff --git a/src/controllers/admin.js b/src/controllers/admin.js index e69de29..360cc1e 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -0,0 +1,9 @@ +const getAdmin = async (req, res, next) => { + try { + res.render("admin", { requestingUser: req.requestingUser, config: { general: {}, api: {} } }); + } catch (err) { + next(err); + } +}; + +module.exports = { getAdmin }; diff --git a/src/controllers/oauth.js b/src/controllers/oauth.js index 7826553..d64acec 100644 --- a/src/controllers/oauth.js +++ b/src/controllers/oauth.js @@ -56,27 +56,9 @@ const interactionUuid = async (req, res, next) => { } if (interaction.prompt.name === "login") { - res.send(` - - -
-