Working up to log in

This commit is contained in:
nugroho 2025-06-01 10:41:52 +07:00
parent 5104dd8e2d
commit 18b552308b
15 changed files with 1946 additions and 9 deletions

53
assets/css/fonts.css Normal file
View File

@ -0,0 +1,53 @@
/* latin-ext */
/* @font-face {
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 300 600;
font-display: block;
src: url(/assets/font/ss3le.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
} */
/* latin */
@font-face {
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 300 600;
font-display: block;
src: url(/assets/fonts/ss3l.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
/* @font-face {
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 300 600;
font-display: block;
src: url(/assets/font/ss3ile.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
} */
/* latin */
@font-face {
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 300 600;
font-display: block;
src: url(/assets/fonts/ss3il.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* arabic */
/* @font-face {
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 400;
font-display: block;
src: url(/assets/font/UthmanicHafs1Ver09.woff2) format('woff2');
unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
} */
/* Material Symbols Outlined */
@font-face {
font-family: 'Material Symbols Outlined';
font-style: normal;
font-weight: 400;
font-display: block;
src: url(/assets/fonts/materials.woff2) format('woff2');
}

545
assets/css/molybdenum.css Executable file
View File

@ -0,0 +1,545 @@
/*!
* molybdenum v1.1.0 Companion CSS
* Copyright 2025 PT Nusa Angkasa Siber
* Released under the MIT License
*/
:root {
color-scheme: light only;
--secondary-table: #1e634a;
--primary-table: #1182a4;
--primary-foreground: #050607;
--secondary-foreground: #aaaaac;
--primary-background: #fefdfc;
--secondary-background: #d9d9dc;
--semi-background: #fdfcf975;
--primary-accent: #1b5d76;
--semi-primary: #1b5d76bb;
--secondary-accent: #4eaacc;
--semi-secondary: #4eaaccbb;
--negative-accent: #ad0400;
--positive-accent: #4ecc89;
--neutral-p-accent: #5fc4ff;
--neutral-n-accent: #f6c267;
--semi-negative: #ad0400bb;
--semi-positive: #4ecc89bb;
--semi-neutral-p: #5fc4ffbb;
--semi-neutral-n: #f6c267bb;
--input-background: #ebf2f4;
--blend-color: inherit;
height: 100vh;
}
* {
box-sizing: border-box;
position: relative;
font-family: 'Source Sans 3';
}
body
{
font-size: 13pt;
color: var(--primary-foreground);
background-color: var(--primary-background);
}
thead
{
background-color: var(--primary-accent);
color: var(--primary-background);
position: sticky;
top: 1px;
z-index: 1;
}
button
{
border: 1px solid var(--secondary-foreground);
color: var(--primary-foreground);
padding: .125em .35em .125em .35em;
border-radius: .15em;
margin: .15em 0 .15em 0;
font-size: .9em;
}
button.accented
{
background-color: var(--primary-accent);
color: var(--primary-background);
}
button.p-accent
{
background-color: var(--neutral-p-accent);
}
button.s-accent
{
background-color: var(--secondary-accent);
}
button.n-accent
{
background-color: var(--neutral-n-accent);
}
button.positive
{
background-color: var(--positive-accent);
}
button.negative
{
background-color: var(--negative-accent);
color: var(--primary-background);
}
button:hover:not(:disabled)
{
filter: brightness(1.15);
}
button:active:not(:disabled)
{
border: 1px inset var(--secondary-foreground);
filter: brightness(.95);
}
button:disabled
{
background-color: var(--secondary-foreground);
color: var(--primary-foreground)
}
table
{
isolation: isolate;
}
table, table th, table td {
border-collapse: collapse;
padding: .2ch .25ch .2ch .25ch;
margin: auto;
}
table.bordered, table.bordered th , table.bordered td {
border: 1px solid var(--primary-background);
}
table.fullwidth{
width: calc(100% - 2ch);
}
table.selectable tr:not(thead tr){
user-select: none;
-webkit-user-select: none;
cursor: pointer;
}
table.selectable tr:hover:not(thead tr)
{
background-color: var(--semi-neutral-p);
}
tr:nth-child(odd):not(thead tr){
background-color: white;
}
tr:not(thead tr){
background-color: var(--input-background);
}
table.selectable tr.selected:not(thead tr), table.selectable tr.odd.selected:not(thead tr){
background-color: var(--semi-positive);
}
table.selectablecell td:hover:not(.block)
{
cursor: pointer;
background-color: var(--semi-neutral-p);
}
table.selectablecell td.selected:not(.block)
{
background-color: var(--semi-positive);
}
textarea
{
min-height: 1.85em;
resize: vertical;
}
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]), textarea, select
{
background-color: var(--primary-background);
border: 1px solid var(--secondary-foreground);
border-radius: .15em;
font-size: 1em;
padding-inline-start: .35em;
padding-inline-end: .35em;
width: 25ch;
outline: none;
margin-bottom: .25em;
}
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):focus-visible, textarea:focus-visible, select:focus-visible
{
border: 1px solid var(--secondary-background);
border-bottom: 1px solid var(--primary-accent);
background-color: var(--input-background);
}
input.icon
{
padding-left: 3.5ch !important;
}
input[type="password"].peek
{
padding-right: 3.5ch !important;
}
sep-bar{
-webkit-user-select: none;
user-select: none;
color: var(--secondary-foreground);
margin-inline-start: .75ch;
margin-inline-end: .5ch;
}
sep-bar::after{
content: "|";
}
background-screen, load-screen, dialog-screen
{
display: flex;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--semi-background);
backdrop-filter: blur(5px);
user-select: none;
justify-content: center;
align-items: center;
-webkit-user-select: none;
-webkit-user-drag: none;
}
load-screen:not(body>load-screen)
{
position: absolute;
}
load-screen
{
flex-direction: column;
}
dialog-box
{
display: grid;
grid-template-rows: auto 1fr;
row-gap: .75em;
position: relative;
max-width: 90vw;
max-height: 90vh;
width: max-content;
height: max-content;
background-color: var(--primary-background);
border: 1px solid var(--secondary-foreground);
border-radius: .25em;
padding: .5em;
transition: scale .25s;
scale: 0;
}
dialog-title
{
display: grid;
grid-template-columns: 1fr auto;
border-bottom: 1px solid var(--secondary-foreground);
font-weight: 500;
padding-left: .25em;
height: 1.65em;
}
load-screen.opaque
{
background-color: var(--primary-background);
}
a, confirm-handle
{
display: inline;
-webkit-user-select: none;
user-select: none;
cursor: pointer;
color: var(--primary-accent);
margin-inline-start: .5ch;
margin-inline-end: .5ch;
white-space: nowrap;
text-decoration: none;
filter: brightness(1);
}
a
{
transition: filter .35s ease, text-shadow .35s ease;
}
a:hover /*, confirm-handle:hover */
{
filter: brightness(1.25);
text-shadow: 0 0 .25em var(--semi-primary);
}
a:active /*, confirm-handle:active*/
{
filter: brightness(1.25);
text-shadow: 0 0 .75em var(--semi-primary);
}
button.notifier::after
{
content: ".";
background-color: var(--negative-accent);
color: var(--negative-accent);
width: 2em;
height: 2em;
border-radius: 1em;
display: block;
position: absolute;
top: -.75em;
right: -.75em;
font-size: .3em;
}
a-button.notifier::after
{
content: ".";
background-color: var(--negative-accent);
color: var(--negative-accent);
width: 2em;
height: 2em;
border-radius: 1em;
display: block;
position: absolute;
top: -.1em;
right: -1.25em;
font-size: .26em;
}
/* .ellipsis
{
display: inline-block;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
max-width: 100%;
} */
.noscroll
{
overflow: hidden;
}
/* ANIMATIONS */
load-message
{
display: block;
margin: .4em;
}
chat-load { /* POSSIBLE load-anim DEFINITION */
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
}
chat-load span { /* ALSO PUT load-anim span IF USED */
width: 1em;
height: 1em;
background-color: var(--primary-accent);
border-radius: 50%;
opacity: 0.3;
animation: pulse 1.5s infinite ease-in-out;
}
chat-load span:nth-child(1) {
animation-delay: 0s;
}
chat-load span:nth-child(2) {
animation-delay: 0.2s;
}
chat-load span:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes pulse {
0%, 100% {
opacity: 0.3;
transform: scale(1);
}
50% {
opacity: 1;
transform: scale(1.3);
}
}
sonar-ping
{ /* POSSIBLE load-anim DEFINITION */
width: 2em;
height: 2em;
border: 2px solid var(--primary-accent);
border-radius: 50%;
position: relative;
animation: expandRing 1.5s infinite ease-out;
}
@keyframes expandRing {
0% {
transform: scale(0.5);
opacity: 1;
}
100% {
transform: scale(2);
opacity: 0;
}
}
skeleton-view {
background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s infinite linear;
border-radius: 4px;
}
@keyframes skeleton-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
progress-loop { /* POSSIBLE load-anim DEFINITION */
width: 95%;
height: .25em;
background: var(--secondary-background);
position: relative;
overflow: hidden;
}
progress-loop::after { /* ALSO PUT load-anim::after IF USED */
content: "";
width: 50%;
height: 100%;
background: var(--primary-accent);
position: absolute;
left: -50%;
animation: progress-loop 2s infinite linear;
}
@keyframes progress-loop {
0% { left: -50%; }
100% { left: 100%; }
}
m-icon {
max-width: 1ch;
width: 1ch;
overflow: hidden;
font-family: 'Material Symbols Outlined';
font-weight: normal;
font-style: normal;
font-size: 1.3em;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
m-inline {
max-width: 1ch;
width: 1ch;
overflow: hidden;
font-family: 'Material Symbols Outlined';
font-weight: normal;
font-style: normal;
font-size: 1.25em;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
padding-bottom: .17em;
vertical-align: middle;
}
button>m-inline
{
padding-bottom: .07em;
}
m-inline.icon
{
position: absolute;
left: 0;
font-size: 1.2em;
padding-top: .25em;
padding-left: .2em;
max-width: 1.2ch;
width: 1.2ch;
}
/* ALERT BOX */
alert-screen, confirm-screen
{
display: flex;
position: fixed !important;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--semi-background);
backdrop-filter: blur(5px);
user-select: none;
justify-content: center;
align-items: center;
-webkit-user-select: none;
-webkit-user-drag: none;
}
alert-box, confirm-box
{
border: 1px solid var(--secondary-foreground);
display: block;
width: calc(100vw - .75em);
max-width: 450px;
position: fixed;
height: 12.25em;
max-height: 12.25em;
padding: .5em;
background-color: var(--semi-background);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
border-radius: .25em;
scale: 0;
transition: scale .25s;
text-align: center;
}
confirm-box
{
height: 14.25em;
max-height: 14.25em;
}
alert-handle
{
display: inline;
-webkit-user-select: none;
user-select: none;
cursor: pointer;
color: var(--primary-accent);
margin-inline-start: .5ch;
margin-inline-end: .5ch;
white-space: nowrap;
text-decoration: none;
filter: brightness(1);
}
confirm-handle
{
display: grid;
grid-template-rows: 1fr 1fr;
position: absolute;
bottom: .25em;
left: -.2em;
right: -.2em;
text-align: center;
height: 3.5em;
outline: none;
color: var(--primary-foreground);
}
alert-title, confirm-title
{
display: block;
white-space: nowrap;
font-weight: 600;
max-width: 100%;
text-overflow: ellipsis;
overflow: hidden;
text-align: center;
margin-bottom: .25em;
border-bottom: 1px solid var(--secondary-background);
}
alert-text, confirm-text
{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 5;
line-clamp: 5;
overflow: hidden;
text-overflow: ellipsis;
padding-top: .25em;
border-bottom: 1px solid var(--secondary-background);
text-align: justify;
height: 7.75em;
margin-bottom: .25em;
}

Binary file not shown.

BIN
assets/fonts/ss3il.woff2 Normal file

Binary file not shown.

BIN
assets/fonts/ss3l.woff2 Normal file

Binary file not shown.

BIN
assets/images/bpn.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -1,3 +1,4 @@
vernum = "1.0.250601.1020"
async function getJson(url,headers={}) {
try {
const response = await fetch(url);

2
assets/js/jquery.min.js vendored Executable file

File diff suppressed because one or more lines are too long

988
assets/js/molybdenum.js Executable file
View File

@ -0,0 +1,988 @@
/*!
* molybdenum v1.1.0
* Copyright 2025 PT Nusa Angkasa Siber
* Released under the MIT License
*/
class molybdenum{
version = '1.1.0';
_alerts = [];
_confirms = [];
_loads = [];
_dialogs = [];
newElement(name = "div", options = {}){
const ele = document.createElement(name);
options.style ? ele.style = options.style : null;
options.className ? ele.className = options.className : null;
typeof options.append === 'string' ? ele.append(options.append) : options.append instanceof Element ? ele.append(options.append) : null;
typeof options.href === 'string' && ele.nodeName === "A" ? ele.setAttribute("href",options.href) : null;
return ele;
}
customElement(name = "div", options = {})
{
const par = document.createElement("div");
par.innerHTML=`<${name}></${name}>`;
const ele = par.firstChild;
options.style ? ele.style = options.style : null;
options.className ? ele.className = options.className : null;
typeof options.append === 'string' ? ele.append(options.append) : options.append instanceof Element ? ele.append(options.append) : null;
typeof options.href === 'string' && ele.nodeName === "A" ? ele.setAttribute("href",options.href) : null;
return ele;
}
loadScreen = class {
static clear()
{
$('load-screen').remove();
moly._loads = [];
}
static show(message = "", style = "sonar", target = "body")
{
if (target != "body" && ($(target).length != 1 || $(target).prevObject))
{
console.error("Target Invalid: " + JSON.stringify($(target)));
return -1;
}
let sid = Date.now() + Math.random().toString(16).slice(2);
let ls = moly.newElement("load-screen");
let lm = moly.newElement("load-message");
lm.append(message);
if (style == "dots")
{
let p = moly.newElement("chat-load")
ls.append(p);
p.append(moly.newElement("span"));
p.append(moly.newElement("span"));
p.append(moly.newElement("span"));
}
else if (style == "bar")
{
ls.append(moly.newElement("progress-loop"));
}
else
{
ls.append(moly.newElement("sonar-ping"));
}
ls.append(lm);
moly._loads.push({id: sid, screen: ls});
$(target).append(ls);
return sid;
}
static update(id=0, message = "")
{
let i = moly._loads.findIndex(e=> e.id == id)
if(i >= 0 && message.length > 0)
{
$(moly._loads[i].screen).children("load-message").html(message);
}
}
static close(id=0)
{
let i = moly._loads.findIndex(e=> e.id == id)
if(i >= 0)
{
moly._loads[i].screen.remove();
moly._loads.splice(i,1);
}
}
}
dialog = class {
static clear()
{
$('dialog-box').remove();
moly._dialogs = [];
}
static async show({ title = "Dialog Box", content = "", fetching = false, data = {} } = {})
{
let dialog =
{
id: Date.now() + Math.random().toString(16).slice(2),
screen: moly.newElement("dialog-screen"),
box: moly.newElement("dialog-box"),
titlet: moly.newElement("span"),
content: moly.newElement("div"),
beforeResolve: [],
resolve: undefined,
data: data
}
moly._dialogs.push(dialog);
dialog.screen.append(dialog.box)
let titlebar = moly.newElement("dialog-title");
let closebtn = moly.newElement("a-button");
let closeicn = moly.newElement("m-icon");
closebtn.append(closeicn)
closeicn.append("close");
closebtn.setAttribute("type","negative");
dialog.box.append(titlebar);
$(dialog.box).css("width",data.width);
$(dialog.box).css("height",data.height);
titlebar.append(dialog.titlet);
$(dialog.titlet).html(title);
titlebar.append(closebtn);
dialog.box.append(dialog.content);
dialog.content.setAttribute("id",`db${dialog.id}`);
dialog.content.style = "overflow-y: auto;"
$('body').append(dialog.screen);
setTimeout(()=>{
$(dialog.box).css("scale",1);
},5);
let loadid = moly.loadScreen.show("Memuat Konten...","sonar",`#db${dialog.id}`);
$(dialog.content).html(fetching ? await fetch(content).then(r => r.text()) : content);
moly.loadScreen.close(loadid);
return new Promise((resolve,reject)=>{
dialog.resolve = function(out)
{
moly.dialog.close(dialog.id);
resolve(out);
}
$(closebtn).click(()=>{
moly.dialog.close(dialog.id);
resolve(false);
});
});
}
static close(id="")
{
let i = moly._dialogs.findIndex(e => e.id == id); //this.screens.findIndex(e=> e.id == id)
if(i >= 0)
{
$(moly._dialogs[i].box).css("scale",0);
setTimeout(() => {
$.each(moly._dialogs[i].beforeResolve, (i,v)=>
{
typeof v == "function" ? v() : false;
});
moly._dialogs[i].screen.remove();
moly._dialogs.splice(i,1);
}, 250);
}
}
static resolve(id = 0, data)
{
let i = moly._dialogs.findIndex(e => e.id == id); //this.screens.findIndex(e=> e.id == id)
if(i >= 0)
{
moly._dialogs[i].resolve(data);
}
}
}
alert = class {
static show(title = "Perhatian", messageHTML = "", timeOut = 0)
{
let alert =
{
id: Date.now() + Math.random().toString(16).slice(2),
screen: moly.newElement("alert-screen"),
box: moly.newElement("alert-box"),
title: moly.newElement("alert-title"),
message: moly.newElement("alert-text"),
handle: moly.newElement("alert-handle")
}
alert.screen.append(alert.box);
alert.box.append(alert.title);
alert.box.append(alert.message);
alert.box.append(alert.handle);
alert.title.innerText = title;
alert.message.innerHTML = messageHTML;
alert.message.setAttribute("title", alert.message.innerText);
if (timeOut >0 ) {alert.handle.innerText = `Tunggu ${timeOut} detik.`;} else {alert.handle.innerText = "Tutup";}
moly._alerts.push(alert);
$('body').append(alert.screen);
setTimeout(() => {
$(alert.box).css("scale",1);
}, 5);
setTimeout(() => {
if ( timeOut > 0)
{
let ms = timeOut * 1000;
let intv = setInterval(()=>{
ms -= 1000;
if (ms <= 0)
{
moly.alert.close(alert.id);
clearInterval(intv);
return;
}
$(moly._alerts.findLast(()=>true).screen).find("alert-handle")[0].innerText = `Tunggu ${ms/1000} detik`;
},1000);
}
else
{
$(alert.handle).click(()=>
{
moly.alert.close(alert.id);
})
}
}, 250);
}
static close(id = "")
{
let ix = moly._alerts.findIndex(e=> e.id == id)
if (ix >= 0)
{
$(moly._alerts[ix].box).css("scale",0);
setTimeout(()=>{
moly._alerts[ix].screen.remove();
moly._alerts.splice(ix,1);
}, 250);
}
}
}
confirm = class {
static show(title = "Anda Yakin?", messageHTML = "", yesLabel = "Yes", noLabel = "No", positiveYes = null, positiveNo = null)
{
let confirm =
{
id: Date.now() + Math.random().toString(16).slice(2),
screen: moly.newElement("confirm-screen"),
box: moly.newElement("confirm-box"),
title: moly.newElement("confirm-title"),
message: moly.newElement("confirm-text"),
handle: moly.newElement("confirm-handle"),
resolve: undefined
}
let yes = moly.newElement("a-button");
let no = moly.newElement("a-button");
confirm.screen.append(confirm.box);
confirm.box.append(confirm.title);
confirm.box.append(confirm.message);
confirm.box.append(confirm.handle);
confirm.title.innerText = title;
confirm.message.innerHTML = messageHTML;
confirm.message.setAttribute("title", confirm.message.innerText);
confirm.handle.append(yes);
confirm.handle.append(no);
yes.innerText = yesLabel;
no.innerText = noLabel;
if (positiveYes == true)
{
yes.setAttribute("type","positive");
}
else if (positiveYes == false)
{
yes.setAttribute("type","negative");
}
else
{
yes.setAttribute("type","blend");
}
if (positiveNo == true)
{
no.setAttribute("type","positive");
}
else if (positiveNo == false)
{
no.setAttribute("type","negative");
}
else
{
no.setAttribute("type","blend");
}
moly._confirms.push(confirm);
$('body').append(confirm.screen);
setTimeout(() => {
$(confirm.box).css("scale",1);
}, 5);
return new Promise((resolve,reject)=>{
confirm.resolve = function(out)
{
moly.confirm.close(confirm.id);
resolve(out);
}
$(no).click(()=>{
moly.confirm.close(confirm.id);
resolve(false);
});
$(yes).click(()=>{
moly.confirm.close(confirm.id);
resolve(true);
});
});
}
static close(id ="")
{
let i = moly._confirms.findIndex(e => e.id == id); //this.screens.findIndex(e=> e.id == id)
if(i >= 0)
{
$(moly._confirms[i].box).css("scale",0);
setTimeout(() => {
moly._confirms[i].screen.remove();
moly._confirms.splice(i,1);
}, 250);
}
}
}
file = class {
static async crc32(file){
let crc32Table = new Uint32Array(256).map((t, c) => {
for (let k = 0; k < 8; k++) {
c = c & 1 ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
}
return c >>> 0;
});
const arrayBuffer = await file.arrayBuffer();
const buf = new Uint8Array(arrayBuffer);
let crc = 0 ^ (-1);
for (let i = 0; i < buf.length; i++) {
crc = (crc >>> 8) ^ crc32Table[(crc ^ buf[i]) & 0xFF];
}
return ((crc ^ (-1)) >>> 0).toString(16).padStart(8, '0').toUpperCase();
};
static async serialise(file = new File([],"")){
let hash = await this.crc32(file);
const reader = new FileReader();
return new Promise((resolve, reject) => {
reader.onload = function(event) {
const base64Data = event.target.result.split(',')[1];
const fileData = {
name: file.name,
type: file.type,
data: base64Data,
crc32: hash
};
resolve(fileData);
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
};
static deserialise(fileData){
const byteCharacters = atob(fileData.data);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: fileData.type });
const file = new File([blob], fileData.name, { type: fileData.type });
return file;
}
}
AButton = class extends HTMLElement
{
static observedAttributes = ["disabled"];
constructor() {
super();
this.attachShadow({ mode: "open" }); // Attach Shadow DOM
this.shadowRoot.innerHTML = `
<style>
:host {
display: inline;
-webkit-user-select: none;
user-select: none;
cursor: pointer;
font-family: 'Source Sans 3';
color: var(--primary-accent);
margin-inline-start: .5ch;
margin-inline-end: .5ch;
white-space: nowrap;
text-decoration: none;
filter: brightness(1);
transition: filter .35s ease, text-shadow .35s ease;
}
:host([disabled]) {
color: var(--secondary-foreground) !important;
pointer-events: none;
}
:host(:hover){
filter: brightness(1.25);
text-shadow: 0 0 .25em var(--semi-primary);
}
:host(:active){
filter: brightness(1.25);
text-shadow: 0 0 .75em var(--semi-primary);
}
:host([type="blend"]), :host([type="peek"])
{
color: inherit;
}
:host([type="blend"]:hover)
{
filter: brightness(4);
text-shadow: none;
}
:host([type="blend"]:active)
{
filter: brightness(8);
text-shadow: none;
}
:host([type="negative"])
{
color: var(--negative-accent);
}
:host([type="negative"]:hover)
{
filter: brightness(1.25);
text-shadow: 0 0 .35em var(--semi-negative);
}
:host([type="negative"]:active)
{
filter: brightness(1.25);
text-shadow: 0 0 .65em var(--semi-negative);
}
:host([type="peek"])
{
text-shadow: none;
position: absolute !important;
padding-top: .25em;
transform: translatex(-3.5ch);
}
</style>
<slot></slot>
`;
}
get disabled() {
return this.hasAttribute("disabled");
}
set disabled(value) {
if (value) {
this.setAttribute("disabled", "");
} else {
this.removeAttribute("disabled");
}
}
}
FileInput = class extends HTMLElement
{
static observedAttributes = ["disabled", "accept", "multiple"];
constructor() {
super();
this.attachShadow({ mode: "open" }); // Attach Shadow DOM
this.shadowRoot.innerHTML = `
<style>
:host
{
display: inline-flex;
width: 25ch;
height: 1.7em;
border: 1px solid var(--secondary-foreground);
user-select: none;
cursor: pointer;
text-align: center;
justify-content: center;
align-items: center;
color: var(--secondary-foreground);
}
div
{
font-size: .8em;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: calc(100%);
padding-inline-start: .75ch;
padding-inline-end: .75ch;
}
</style>
`;
this._input = document.createElement("input");
this._input.type = "file";
this._input.setAttribute("hidden","");
this._handleChange = this._handleChange.bind(this);
this._handleClick = this._handleClick.bind(this);
this._label = document.createElement("div");
}
connectedCallback()
{
this._input.addEventListener("change", this._handleChange);
this.shadowRoot.appendChild(this._input);
this.shadowRoot.appendChild(this._label);
this._label.innerText = "Click to select a file.";
this.addEventListener("click", this._handleClick);
if (this.getAttribute("accept"))
{
this._input.setAttribute("accept", this.accept);
this.accept = this.getAttribute("accept");
}
if (this.hasAttribute("multiple"))
{
this._input.setAttribute("multiple", "");
this.multiple = this.hasAttribute("multiple");
this._label.innerText = "Click to select files.";
}
}
disconnectedCallback() {
this._input.removeEventListener("change", this._handleChange);
}
_handleChange(event)
{
if (this.hasAttribute("multiple") && this._input.files.length == 1)
{
this._label.innerText = `${this._input.files[0].name} selected.`;
}
else if (this.hasAttribute("multiple") && this._input.files.length > 1)
{
this._label.innerText = `${this._input.files.length} files selected.`
}
else if (this.hasAttribute("multiple"))
{
this._label.innerText = "Click to select files.";
}
else if (this._input.files.length == 1)
{
this._label.innerText = `${this._input.files[0].name} selected.`;
}
else
{
this._label.innerText = "Click to select a file.";
}
this.dispatchEvent(new CustomEvent("change", {bubble: true, composed: true, detail: this.files}));
}
_handleClick(event)
{
this._input.click();
}
get disabled() {
return this.hasAttribute("disabled");
}
set disabled(value) {
if (value) {
this.setAttribute("disabled", "");
} else {
this.removeAttribute("disabled");
}
}
get files() {
return this._input.files;
}
set accept(value) {
if (value) {
this._input.accept = value;
this.setAttribute("accept", value); // Keep the attribute in sync
} else {
this._input.removeAttribute("accept");
this.removeAttribute("accept");
}
}
get accept() {
return this._input.accept;
}
set multiple(value) {
if (value) {
this._input.setAttribute("multiple", "");
this.setAttribute("multiple", "");
this._label.innerText = "Click to select files.";
} else {
this._input.removeAttribute("multiple");
this.removeAttribute("multiple");
this._label.innerText = "Click to select a file.";
}
this._input.value = "";
}
get multiple() {
return this._input.hasAttribute("multiple");
}
reset()
{
this._input.value = "";
if (this.hasAttribute("multiple"))
{
this._label.innerText = "Click to select files.";
}
else
{
this._label.innerText = "Click to select a file.";
}
return this._input.files.length;
}
}
Group = class extends HTMLElement
{
static observedAttributes = ["label", "type", "collapsed"];
constructor()
{
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = `
<style>
:host
{
display: block;
padding: .5em .25em .5em .75em;
margin: .25em;
margin-top: 1em;
border-top: 1px solid var(--secondary-foreground);
}
:host([type="box"])
{
border: 1px solid var(--secondary-foreground);
}
:host([collapsed]:not([type="box"]))
{
padding: .35em;
}
:host([type="box"][collapsed])
{
padding: .32em;
}
group-label
{
display: inline-block;
background-color: var(--primary-background);
position: absolute;
top: -.85em;
left: .5ch;
padding-left: .25ch;
padding-right: .25ch;
}
:host([collapsed]) group-content
{
display: none;
}
m-inline
{
max-width: 1ch;
width: 1ch;
overflow: hidden;
font-family: 'Material Symbols Outlined';
font-weight: normal;
font-style: normal;
font-size: 1.25em;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
padding-bottom: .1em;
vertical-align: middle;
}
a-button
{
margin: 0;
}
</style>
<group-label><a-button><span></span> <m-inline></m-inline></a-button></group-label>
<group-content><slot></slot></group-content>
`;
this._labelText = $(this.shadowRoot).children("group-label").children("a-button").children("span");
this._labelIcon = $(this.shadowRoot).children("group-label").children("a-button").children("m-inline");
}
connectedCallback()
{
if (this.label && this.label.length > 0)
{
$(this.shadowRoot).children("group-label").children("a-button").children("span").text(this.label);
}
else
{
$(this.shadowRoot).children("group-label").children("a-button").children("span").text("Group Label");
}
if (this.collapsed)
{
$(this.shadowRoot).children("group-label").children("a-button").children("m-inline").text("expand_more");
}
else
{
$(this.shadowRoot).children("group-label").children("a-button").children("m-inline").text("expand_less");
}
$(this.shadowRoot).children("group-label").children("a-button").click(()=>
{
this.collapsed = !this.collapsed;
});
}
disconnectedCallback()
{
$(this.shadowRoot).children("group-label").children("a-button").off("click");
}
attributeChangedCallback(name, oldValue, newValue)
{
if (name === "label")
{
if (this.label && this.label.length > 0)
{
this._labelText.text(this.label);
}
else
{
this._labelText.text("Group Label");
}
}
else if (name === "collapsed")
{
if (this.collapsed)
{
this._labelIcon.text("expand_more");
}
else
{
this._labelIcon.text("expand_less");
}
}
}
get collapsed() {
return this.hasAttribute("collapsed");
}
set collapsed(value) {
if (value) {
this.setAttribute("collapsed", "");
} else {
this.removeAttribute("collapsed");
}
}
get label() {
return this.getAttribute("label");
}
set label(value) {
this.setAttribute("label", value.toString());
}
get type() {
return this.getAttribute("type");
}
set type(value) {
this.setAttribute("type", value.toString());
}
}
VSpacer = class extends HTMLElement
{
static observedAttributes = ["lines"];
constructor()
{
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = `
<style>
:host
{
display: block;
}
</style>
<div></div>
`;
this._div = $(this.shadowRoot).children("div");
}
connectedCallback(){
this._applyHeight();
}
attributeChangedCallback(name, oldValue, newValue)
{
if (name === "lines")
{
this._applyHeight();
}
}
_applyHeight()
{
const height = (!this.lines || isNaN(this.lines)) ? 1 : this.lines
this._div.css("height",`${height}lh`);
}
get lines() {
return Number(this.getAttribute("lines"));
}
set lines(value) {
if (isNaN(value))
{
this.setAttribute("lines", 1);
}
else
{
this.setAttribute("lines", Number(value));
}
}
}
MultiLineEllipsis = class extends HTMLElement
{
static observedAttributes = ["lines"];
constructor()
{
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = `
<style>
:host
{
display: block;
}
div
{
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<div><slot></slot></div>
`;
this._div = $(this.shadowRoot).children("div");
this._slot = $(this.shadowRoot).find("slot");
}
connectedCallback(){
this._applyLineClamp();
this.title = this.innerText;
this._slot.on("slotchange", ()=>{this.title = this.innerText;});
}
attributeChangedCallback(name, oldValue, newValue)
{
if (name === "lines")
{
this._applyLineClamp();
}
}
_applyLineClamp()
{
const lines = (!this.lines || isNaN(this.lines)) ? "1" : this.lines.toString();
this._div.css({
"line-clamp": lines,
"-webkit-line-clamp": lines
});
}
get lines() {
return Number(this.getAttribute("lines"));
}
set lines(value) {
if (isNaN(value))
{
this.setAttribute("lines", 1);
}
else
{
this.setAttribute("lines", Number(value));
}
}
}
MidlineEllipsis = class extends HTMLElement
{
static observedAttributes = ["chars"];
constructor()
{
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = `
<style>
:host
{
display: inline;
cursor: pointer;
}
</style>
<slot></slot>
`;
}
connectedCallback(){
this.title = this.innerText;
this._chars = Number(this.getAttribute("chars"));
this._chars > 5 ? 1==1 : this.chars = 5;
this._originalNodes = this.cloneNode(true);
this._applyEllipsis();
this.addEventListener("click",()=>{
moly.alert.show("Konten Lengkap",this._originalNodes.innerHTML);
})
}
disconnectedCallback()
{
this.removeEventListener("click");
}
_applyEllipsis()
{
let sourceNodes = this._originalNodes.cloneNode(true).childNodes;
let skip = ["a-button","button", "img"];
let fhalftl = Math.ceil((this.chars-3)/2);
let lhalftl = Math.floor((this.chars-3)/2);
let fhalfl = 0;
let lhalfl = 0;
let fsearch = true;
let fpart = moly.newElement("span");
let lpart = moly.newElement("span");
let title = "";
$.each(sourceNodes,(i,v)=>{
if (skip.includes(v.nodeName.toLowerCase())) return;
title += v.textContent;
if(fsearch && v.textContent.length > 0 )
{
if (fhalfl + v.textContent.length < fhalftl)
{
fpart.append(v.cloneNode(true));
}
else
{
let remaining = fhalftl - fhalfl ;
let snode = v.cloneNode(true);
snode.textContent = snode.textContent.substring(0,remaining);
if(snode.textContent.length>0) fpart.append(snode);
fpart.append("...");
fsearch = false;
}
fhalfl += v.textContent.length;
}
});
this.title = title.replace(/\s+/g, ' ').trim();
for (let i = sourceNodes.length - 1; i >= 0; i--) {
let v = sourceNodes[i];
if (skip.includes(v.nodeName.toLowerCase())) continue;
if(v.textContent.length > 0 )
{
if (lhalfl + v.textContent.length < lhalftl)
{
lpart.prepend(v.cloneNode(true));
}
else
{
let remaining = lhalftl - lhalfl;
let snode = v.cloneNode(true);
snode.textContent = snode.textContent.substring(snode.textContent.length-remaining);
if(snode.textContent.length>0) lpart.prepend(snode);
break;
}
lhalfl += v.textContent.length;
}
}
fpart.innerHTML = fpart.innerHTML.trim();
lpart.innerHTML = lpart.innerHTML.trim()
$(this).empty().append(...fpart.childNodes,...lpart.childNodes);
}
attributeChangedCallback(name, oldValue, newValue)
{
if (name === "chars")
{
if (this._originalNodes) this._applyEllipsis();
}
}
get chars() {
let retval;
this._chars = Number(this.getAttribute("chars"));
this._chars > 5 ? retval = this._chars : retval = 5;
return retval;
}
set chars(value) {
if (isNaN(value))
{
this._chars = 5
this.setAttribute("chars", 5);
}
else
{
this._chars = Number(value);
this.setAttribute("chars", this._chars > 5 ? this.chars : 5);
}
}
}
}
(async ()=>{
let time = 0
while (typeof window.jQuery === "undefined" && time < 10000) {
await new Promise(resolve => setTimeout(resolve, 50));
time +=50;
}
if (window.jQuery)
{
window.moly = new molybdenum();
customElements.define("a-button",moly.AButton);
customElements.define("file-input",moly.FileInput);
customElements.define("group-el",moly.Group);
customElements.define("v-spacer",moly.VSpacer);
customElements.define("multi-ellipsis",moly.MultiLineEllipsis);
customElements.define("midline-ellipsis",moly.MidlineEllipsis);
}
})();

View File

@ -1,18 +1,254 @@
<!DOCTYPE html>
<html lang="id">
<html lang="en-gb" translate="no">
<head>
<title>Agen Perubahan</title>
<script src="/assets/js/app.js"
></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width initial-scale=1.0, maximum-scale=1.0"/>
<link rel="icon" type="image/webp" href="/assets/images/bpn.webp">
<title>Agen Perubahan Admin Panel</title>
<link rel="preload" href="/assets/fonts/materials.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/assets/fonts/ss3l.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/assets/fonts/ss3il.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="stylesheet" href="/assets/css/fonts.css">
<link rel="stylesheet" href="/assets/css/molybdenum.css">
<script src="/assets/js/jquery.min.js" async></script>
<script src="/assets/js/molybdenum.js" type="module" async></script>
<script src="/assets/js/app.js" async></script>
<style>
html
*
{
background-color: dimgray;
color: lightgray;
user-select: none;
-webkit-user-select: none;
}
*::-webkit-scrollbar, .main::-webkit-scrollbar {
width: .8ch;
}
/* Scrollbar thumb (the draggable part) */
*::-webkit-scrollbar-thumb, .main::-webkit-scrollbar-thumb {
background: var(--secondary-background); /* Dark semi-transparent */
border-radius: .2ch; /* Rounded edges */
}
/* body
{
height: 100%;
} */
h2, h3, h4
{
margin: .25em 0;
}
aside
{
display: block;
position: absolute;
top: 0;
left: 0;
min-height: 100%;
width: 30ch;
background-color: var(--primary-table);
color: var(--primary-foreground);
padding: .5ch;
padding-top: 3.5em;
box-shadow: var(--primary-foreground) .65ch 0, inset var(--primary-foreground) -13px 0 20px -25px;
}
.logobox
{
height: 3em;
position: fixed;
top: .5ch;
left: 0;
width: inherit;
padding: 0 .5ch .5ch .5ch;
border-bottom: 1px solid var(--secondary-background);
}
.sidebar
{
display: block;
position: absolute;
top: calc(3em + 1ch);
left: 0;
width: calc(100% - .25ch);
max-height: calc(100% - (3em + 1.5ch));
overflow-x: auto;
}
.sidebar::-webkit-scrollbar, .main::-webkit-scrollbar {
width: .8ch;
}
/* Scrollbar thumb (the draggable part) */
.sidebar::-webkit-scrollbar-thumb, .main::-webkit-scrollbar-thumb {
background: var(--secondary-background); /* Dark semi-transparent */
border-radius: .2ch; /* Rounded edges */
}
.item
{
height: 2em;
line-height: 2em;
margin-left: 1ch;
margin-right: 1ch;
background-color: var(--primary-table);
padding-left: 1ch;
padding-right: 1ch;
border-radius: .25ch;
cursor: default;
user-select: none;
}
.item:hover
{
filter: brightness(1.2);
}
.item[data-active]
{
filter: brightness(1.4);
}
.sub.item
{
padding-left: 3ch;
}
#main
{
display: block;
position: relative;
margin-left: 30ch;
padding: .5ch .5ch .5ch 0;
height: 100%;
overflow: auto;
backdrop-filter: blur(7px);
background-color: var(--semi-background);
}
nav
{
display: grid;
grid-template-columns: auto 1fr auto;
height: 3em;
padding-left: 2ch;
padding-right: 2ch;
line-height: 3em;
border-bottom: 1px solid var(--input-background);
}
#content
{
display: block;
width: 100%;
min-height: calc(100% - 6em);
padding: .5ch 1ch;
}
#footer
{
height: 3em;
padding: .5em;
line-height: 2em;
border-top: 1px solid var(--input-background);
display: grid;
grid-template-columns: auto 1fr auto;
color: var(--secondary-foreground);
}
</style>
</head>
<body>
Agen Perubahan
<body style="margin: 0; height: 100%; background-color: var(--primary-background);">
<load-screen id="blocker" style="background-color : #fefdfc ; z-index: 1;"><sonar-ping></sonar-ping><load-message>Memuat Aplikasi...</load-message></load-screen>
<aside>
<div class="logobox">
<img src="/assets/images/logo-text.png" style="width: 100%; height: 100%; object-fit: contain; object-position: 1.5ch center;">
</div>
<div class="sidebar">
<div class="item" data-path="dasbor">
<m-inline>dashboard</m-inline> Dasbor
</div>
<div class="item" data-path="kegiatan">
<m-inline>supervisor_account</m-inline> Kegiatan dan Dokumentasi
</div>
<div class="item" data-path="agen">
<m-inline>supervisor_account</m-inline> Manajemen Agen & User
</div>
<div class="item" data-path="laporan">
<m-inline>quick_references</m-inline> Laporan
</div>
</div>
</aside>
<div id="main">
<nav>
<div>
<span>
Agen Perubahan ATR/BPN Kanwil Riau
</span>
</div>
&nbsp;
<div>
<span id="username">User Name</span>
<sep-bar></sep-bar>
<a-button type="blend" id="lo"><m-inline>logout</m-inline> Keluar</a-button>
</div>
</nav>
<div id="content">
</div>
<div id="footer">
<span>Agen Perubahan Admin Panel <span id="vernum"></span></span>
&nbsp;
<span>ATR/BPN Kantor Wilayah Provinsi Riau</span>
</div>
</div>
</body>
<script type="module">
let detail = await fetch("/auth/me").then(r=>r.json()).catch(e=>{
moly.alert.show("Koneksi Gagal","Gagal menyambung ke server. Harap periksa koneksi jaringan.");
return {status: 0};
});
if (detail.status == 401)
{
location = "/login.html";
}
window.agents = (await fetch("/api/getagents").then(r=>r.json()).catch(e=>{
moly.alert.show("Koneksi Gagal","Gagal menyambung ke server. Harap periksa koneksi jaringan.");
return {data: []};
})).data;
const userDetails = detail.data;
const loggedInAgent = agents.find(a=>a.agentID == userDetails.agentID)
// if (!window.evtSource) window.evtSource = new EventSource("/events");
window.addEventListener("viewChange", async ()=>{
if (window.evtSource) evtSource.onmessage = null;
});
async function domReady()
{
$('#vernum').text(`v${vernum}`)
$('#lo').click(async()=>{
const res = await fetch('/auth/logout').catch(e=>{
moly.alert.show("Logout: Koneksi Gagal","Gagal menyambung ke server. Harap periksa koneksi jaringan.");
return {status: 0};
});
if(res.status == 200) location = "/login.html";
});
$('#username').text(loggedInAgent.name)
$('.item, .subitem').click(async (e)=>{
if (window.shellnavigating) return;
window.dispatchEvent(new Event("viewChange"));
window.shellnavigating = true;
let id = moly.loadScreen.show("Memuat...","sonar","#content");
$('.item[data-active]').removeAttr("data-active");
$(e.target.closest(".item")).attr("data-active","");
let content = e.target.closest(".item").getAttribute("data-path") ? fetch(`/modules/${e.target.closest(".item").getAttribute("data-path")}.html`).then(d => d.text()).catch(e=>{
return "Gagal menyambung ke server. Harap periksa koneksi jaringan.";
}) : "";
$('#content').html(await content);
moly.loadScreen.close(id);
window.shellnavigating = false;
});
$('#blocker').remove();
$($('.item')[0]).trigger("click");
}
(async ()=>{
let time = 0
while (typeof window.moly === "undefined" && time < 10000) {
await new Promise(resolve => setTimeout(resolve, 50));
time += 50;
}
if (window.moly)
{
while (typeof window.moly !== "undefined" && document.readyState !== "complete") {
await new Promise(resolve => setTimeout(resolve, 100));
}
domReady();
}
})()
</script>
</html>

112
login.html Normal file
View File

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en-gb" translate="no">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width initial-scale=1.0, maximum-scale=1.0"/>
<link rel="icon" type="image/webp" href="/assets/images/bpn.webp">
<title>Agen Perubahan ATR/BPN Riau</title>
<link rel="preload" href="/assets/fonts/materials.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/assets/fonts/ss3l.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/assets/fonts/ss3il.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="stylesheet" href="/assets/css/fonts.css">
<link rel="stylesheet" href="/assets/css/molybdenum.css">
<script src="/assets/js/jquery.min.js" async></script>
<script src="/assets/js/molybdenum.js" async></script>
<script src="/assets/js/app.js" async></script>
<style>
*
{
user-select: none;
-webkit-user-select: none;
}
input
{
user-select: text;
-webkit-user-select: text;
}
*::-webkit-scrollbar, .main::-webkit-scrollbar {
width: .8ch;
}
/* Scrollbar thumb (the draggable part) */
*::-webkit-scrollbar-thumb, .main::-webkit-scrollbar-thumb {
background: var(--secondary-background); /* Dark semi-transparent */
border-radius: .2ch; /* Rounded edges */
}
</style>
</head>
<body style="margin: 0; height: 100%;">
<load-screen id="blocker" style="background-color : #fefdfc ; z-index: 1;"><sonar-ping></sonar-ping><load-message>Memuat Aplikasi...</load-message></load-screen>
<div style="display: flex; justify-content: center; align-items: center; width: 100%; height: calc(100% - 2.4em); background-color: var(--secondary-background); flex-direction: column; background-image: url(/assets/images/bpn.webp); background-position-x: center; background-repeat: no-repeat;">
<div style="width: 40ch; padding: 1.5ch; background-color: var(--semi-background); backdrop-filter: blur(3px);" id="box">
<h3 style="text-align: center;"><span id="mt">Agen Perubahan ATR/BPN<br>Kantor Wilayah Provinsi Riau</span></h3>
<div style="margin: auto; width: max-content;">
<input id="uname" type="text" class="icon" placeholder="Username"><m-inline class="icon">person</m-inline><br>
<input id="pwd" type="password" class="icon peek" placeholder="Password"><m-inline class="icon">password</m-inline><a-button id="peeker" type="peek"><m-inline>visibility_on</m-inline></a-button><br>
</div>
<div style="text-align: center;">
<button id="login-btn"><m-inline>key</m-inline> Masuk</button>
</div>
</div>
</div>
<div style="height: 3em; background-color: var(--secondary-background); text-align: center; font-size: .8em;">
Agen Perubahan ATR/BPN Kanwil Riau <span id="vernum"></span><br>
Kementerian ATR/BPN Kantor Wilayah Provinsi Riau
</div>
</body>
<script type="module">
async function domReady()
{
$('#vernum').text("versi " + vernum);
window.detail = await fetch("/auth/me");
if(detail.status != 401)
{
location = "/";
return;
}
$('#blocker').remove();
$('#login-btn').click(async ()=>{
await login();
});
$('#pwd, #uname').on("keypress", async (e)=>{
if (e.keyCode == 13) await login();
});
}
(async ()=>{
let time = 0
while (typeof window.moly === "undefined" && time < 10000) {
await new Promise(resolve => setTimeout(resolve, 50));
time += 50;
}
if (window.moly)
{
while (typeof window.moly !== "undefined" && document.readyState !== "complete") {
await new Promise(resolve => setTimeout(resolve, 100));
}
domReady();
}
})();
async function login()
{
$('#uname').prop("disabled",true);
$('#pwd').prop("disabled",true);
$('#peeker').prop("disabled",true);
$('#login-btn').prop("disabled",true);
$('#login-btn').html("<m-inline>hourglass_empty</m-inline> Tunggu");
let login = await fetch("/auth/login",{method: "post", headers: {"content-type": "application/json"}, body: JSON.stringify({username:$('#uname').val(), password:$('#pwd').val()})});
if(login.status == 200)
{
location = "/";
}
else
{
$('#uname').prop("disabled",false);
$('#pwd').prop("disabled",false);
$('#peeker').prop("disabled",false);
$('#login-btn').prop("disabled",false);
$('#login-btn').html("<m-inline>key</m-inline> Masuk");
moly.alert.show("Login Gagal","Tidak dapat login dengan username dan password yang diberikan. Pastikan username dan password sudah benar dan akun dalam keadaan aktif. Hubungi admin untuk informasi lebih lanjut.")
}
}
</script>
</html>

0
modules/agen.html Normal file
View File

0
modules/dasbor.html Normal file
View File

0
modules/kegiatan.html Normal file
View File

0
modules/laporan.html Normal file
View File