list sitekey: copy sitekey

This commit is contained in:
realaravinth
2021-07-15 18:07:12 +05:30
parent 97db774e70
commit 863d22f62c
25 changed files with 369 additions and 224 deletions

View File

@@ -56,7 +56,7 @@ const submit = async (e: Event) => {
const res = await fetch(formUrl, genJsonPayload(payload));
if (res.ok) {
const data = await res.json();
window.location.assign(VIEWS.listSitekey(data.key));
window.location.assign(VIEWS.viewSitekey(data.key));
} else {
const err = await res.json();
createError(err.error);

View File

@@ -18,38 +18,87 @@
@import '../../../../reset';
@import '../../../../vars';
@import '../../../../components/box';
@import '../../../../components/table/main';
.sitekey-list__box {
@include box;
padding-bottom: 0px;
.sitekey__table {
@include table;
margin: auto;
}
.sitekey-list__title {
@include box-title;
}
.sitekey-list__item-container {
display: block;
width: 100%;
box-sizing: border-box;
border-bottom: 0.1px solid $light-grey;
padding: 20px;
color: $black-text;
}
.sitekey-list__item {
display: flex;
width: 100%;
}
.sitekey-list__item-container:hover {
background-color: $light-grey;
.sitekey__table-title-text {
@include table__title-text;
}
.sitekey-list__name {
flex: 3;
min-width: 450px;
}
.sitekey-list__key {
flex: 1;
width: 10px;
}
@mixin copy-icon-base {
margin: auto;
padding: 5px;
}
.sitekey__copy-icon {
@include copy-icon-base;
}
.sitekey__copy-icon:hover {
cursor: pointer;
filter: invert(17%) sepia(93%) saturate(5039%) hue-rotate(204deg)
brightness(100%) contrast(98%);
}
.sitekey__copy-done-icon {
@include copy-icon-base;
display: none;
filter: invert(58%) sepia(60%) saturate(331%) hue-rotate(76deg)
brightness(91%) contrast(92%);
}
.sitekey__key-container {
border-radius: 10px;
background: $backdrop;
margin: 2px;
padding: 5px;
display: flex;
max-width: 150px;
border: 0.1px solid rgba(0, 0, 0, 0.125);
}
.sitekey__widget-link {
border-left: 0.1px solid $light-grey;
margin: 5;
margin: auto;
padding-left: 20px;
height: 100%;
padding-right: 15px;
}
.sitekey-list__sitekey-link {
display: inline-block;
width: 100%;
text-decoration: none;
color: $blue-link;
padding: 20px;
}
.sitekey-list__sitekey-link:visited {
color: $blue-link;
}
.sitekey-list__sitekey-link:hover {
background-color: $light-grey;
cursor: pointer;
}
.sitekey__widget-link {
color: $blue-link;
}
.sitekey__widget-link:visited {
color: $blue-link;
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
.sitekey-list__name {
min-width: 120px;
}

View File

@@ -1,23 +1,53 @@
<. include!("../../../components/headers/index.html"); .>
<. include!("../../navbar/index.html"); .>
<. include!("../../../components/headers/index.html"); .> <.
include!("../../navbar/index.html"); .>
<div class="tmp-layout">
<. include!("../../header/index.html"); .>
<main class="panel-main">
<.include!("../../help-banner/index.html"); .>
<!-- Main content container -->
<div class="inner-container">
<!-- Main menu/ important actions roaster -->
<ul class="sitekey-list__box">
<h1 class="sitekey-list__title">Your Sitekeys</h1>
<. for sitekey in sitekeys.iter() { .>
<a href="/sitekey/<.= sitekey.key .>/" class="sitekey-list__item-container">
<li class="sitekey-list__item">
<span class="sitekey-list__name"><.= sitekey.name .></span>
<span class="sitekey-list__key"><.= sitekey.key .></span>
</li>
</a>
<. } .>
</ul>
</div>
<!-- end of container -->
<. include!("../../../components/footers.html"); .>
<. include!("../../header/index.html"); .>
<main class="panel-main">
<.include!("../../help-banner/index.html"); .>
<!-- Main content container -->
<div class="inner-container">
<!-- Main menu/ important actions roaster -->
<table class="sitekey__table">
<thead class="sitekey__table-heading">
<tr>
<th colspan="4" class="sitekey__table-title-text">
Your Sitekeys
</th>
</tr>
</thead>
<tbody class="sitekey__body">
<. for sitekey in sitekeys.iter() { .>
<tr class="sitekey__item">
<td class="sitekey-list__name">
<a
href="/sitekey/<.= sitekey.key .>/"
class="sitekey-list__sitekey-link"
>
<.= sitekey.name .>
</a>
</td>
<td class="sitekey-list__key">
<div class="sitekey__key-container">
<img class="sitekey__copy-icon" src="<.= crate::FILES
.get("./static/cache/img/svg/clipboard.svg") .unwrap() .>"
alt="copy sitekey" data-sitekey="<.= sitekey.key .>" /> <img
class="sitekey__copy-done-icon" src="<.= crate::FILES
.get("./static/cache/img/svg/check.svg") .unwrap() .>"
alt="sitekey copied" data-sitekey="<.= sitekey.key .>" />
<a
class="sitekey__widget-link"
href="<.= crate::WIDGET_ROUTES.verification_widget .>/?sitekey=<.= sitekey.key .>"
>
<.= &sitekey.key[0..5] .>
</a>
</div>
</td>
</tr>
<. } .>
</tbody>
</table>
</div>
<!-- end of container -->
<. include!("../../../components/footers.html"); .>
</main>
</div>

View File

@@ -15,4 +15,39 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export const index = () => {};
export const index = () => {
registerCopySitekey();
};
const SITEKEY_COPY_ICON = `sitekey__copy-icon`;
const SITEKEY_COPY_DONE_ICON = `sitekey__copy-done-icon`;
const registerCopySitekey = () => {
const icons = document.querySelectorAll(`.${SITEKEY_COPY_ICON}`);
icons.forEach(icon => {
icon.addEventListener('click', e => copySitekey(e));
});
};
/*
* Copy sitekey to clipboard
*/
const copySitekey = async (e: Event) => {
const image = <HTMLElement>e.target;
if (!image.classList.contains(SITEKEY_COPY_ICON)) {
throw new Error(
'This method should only be called when sitekey copy button/icon is clicked',
);
}
const copyDoneIcon = <HTMLElement>(
image.parentElement.querySelector(`.${SITEKEY_COPY_DONE_ICON}`)
);
const sitekey = image.dataset.sitekey;
await navigator.clipboard.writeText(sitekey);
image.style.display = 'none';
copyDoneIcon.style.display = 'block';
setTimeout(() => {
copyDoneIcon.style.display = 'none';
image.style.display = 'block';
}, 1200);
};

View File

@@ -8,47 +8,51 @@
<!-- Main content container -->
<div class="inner-container">
<!-- Main menu/ important actions roaster -->
<form class="sitekey-form" action="<.= crate::V1_API_ROUTES.levels.add .>" method="post">
<h1 class="form__title">Sitekey: <.= name .>
<a href="<.= crate::WIDGET_ROUTES.verification_widget .>/?sitekey=<.= key.>"
>Click here to see CAPTCHA widget in action</a>
</h1>
<label class="sitekey-form__label" for="description">
Description
<input
readonly="readonly"
class="sitekey-form__input"
type="text"
name="description"
id="description"
required
<. if !name.trim().is_empty() { .>
value="<.= name .>"
<. } .>
/>
</label>
<label class="sitekey-form__label" for="duration">
Cooldown Duratoin(in seconds)
<input
readonly="readonly"
class="sitekey-form__input"
type="number"
name="duration"
id="duration"
min=0
required
value="<.= duration .>"
/>
</label>
<. for (count, level) in levels.iter().enumerate() { .>
<. include!("./existing-level.html"); .>
<. } .>
</form>
<form class="sitekey-form" action="<.= crate::V1_API_ROUTES.levels.add .>" method="post">
<h1 class="form__title">Sitekey: <.= name .>
<a
target="_blank"
href="<.= crate::WIDGET_ROUTES.verification_widget .>/?sitekey=<.= key.>"
>View widget
<img class="sitekey-form__widget-link"
src="<.= crate::FILES.get("./static/cache/img/svg/external-link.svg").unwrap() .>"
alt="View widget deployment"
/>
</a>
</h1>
<label class="sitekey-form__label" for="description">
Description
<input
readonly="readonly"
class="sitekey-form__input"
type="text"
name="description"
id="description"
required
<. if !name.trim().is_empty() { .>
value="<.= name .>"
<. } .>
/>
</label>
<label class="sitekey-form__label" for="duration">
Cooldown Duratoin(in seconds)
<input
readonly="readonly"
class="sitekey-form__input"
type="number"
name="duration"
id="duration"
min=0
required
value="<.= duration .>"
/>
</label>
<. for (count, level) in levels.iter().enumerate() { .>
<. include!("./existing-level.html"); .>
<. } .>
</form>
</div>
<!-- end of container -->
<. include!("../../../components/footers.html"); .>