removed remainder of old personal dashboard code. fixed big lighthouse issues.
This commit is contained in:
parent
85d27c5bba
commit
0f05018cab
@ -24,10 +24,11 @@ CREATE TABLE reminder_template (
|
|||||||
`embed_author` VARCHAR(256) NOT NULL DEFAULT '',
|
`embed_author` VARCHAR(256) NOT NULL DEFAULT '',
|
||||||
`embed_author_url` VARCHAR(512),
|
`embed_author_url` VARCHAR(512),
|
||||||
`embed_color` INT UNSIGNED NOT NULL DEFAULT 0x0,
|
`embed_color` INT UNSIGNED NOT NULL DEFAULT 0x0,
|
||||||
|
`embed_fields` JSON,
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
|
|
||||||
FOREIGN KEY (`guild_id`) REFERENCES channels (`id`) ON DELETE CASCADE
|
FOREIGN KEY (`guild_id`) REFERENCES guilds (`id`) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
ALTER TABLE reminders ADD COLUMN embed_fields JSON;
|
ALTER TABLE reminders ADD COLUMN embed_fields JSON;
|
||||||
|
@ -11,7 +11,8 @@ use std::{collections::HashMap, env};
|
|||||||
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
|
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
|
||||||
use rocket::{
|
use rocket::{
|
||||||
fs::FileServer,
|
fs::FileServer,
|
||||||
serde::json::{json, Json, Value as JsonValue},
|
serde::json::{json, Value as JsonValue},
|
||||||
|
shield::Shield,
|
||||||
tokio::sync::broadcast::Sender,
|
tokio::sync::broadcast::Sender,
|
||||||
};
|
};
|
||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
@ -119,12 +120,15 @@ pub async fn initialize(
|
|||||||
.mount(
|
.mount(
|
||||||
"/dashboard",
|
"/dashboard",
|
||||||
routes![
|
routes![
|
||||||
|
routes::dashboard::dashboard,
|
||||||
routes::dashboard::dashboard_home,
|
routes::dashboard::dashboard_home,
|
||||||
routes::dashboard::user::get_user_info,
|
routes::dashboard::user::get_user_info,
|
||||||
routes::dashboard::user::update_user_info,
|
routes::dashboard::user::update_user_info,
|
||||||
routes::dashboard::user::get_user_guilds,
|
routes::dashboard::user::get_user_guilds,
|
||||||
routes::dashboard::guild::get_guild_channels,
|
routes::dashboard::guild::get_guild_channels,
|
||||||
routes::dashboard::guild::get_guild_roles,
|
routes::dashboard::guild::get_guild_roles,
|
||||||
|
routes::dashboard::guild::get_reminder_templates,
|
||||||
|
routes::dashboard::guild::create_reminder_template,
|
||||||
routes::dashboard::guild::create_reminder,
|
routes::dashboard::guild::create_reminder,
|
||||||
routes::dashboard::guild::get_reminders,
|
routes::dashboard::guild::get_reminders,
|
||||||
routes::dashboard::guild::edit_reminder,
|
routes::dashboard::guild::edit_reminder,
|
||||||
|
@ -24,8 +24,8 @@ use crate::{
|
|||||||
MAX_URL_LENGTH, MAX_USERNAME_LENGTH, MIN_INTERVAL,
|
MAX_URL_LENGTH, MAX_USERNAME_LENGTH, MIN_INTERVAL,
|
||||||
},
|
},
|
||||||
routes::dashboard::{
|
routes::dashboard::{
|
||||||
create_database_channel, generate_uid, name_default, DeleteReminder, PatchReminder,
|
create_database_channel, generate_uid, name_default, template_name_default, DeleteReminder,
|
||||||
Reminder,
|
PatchReminder, Reminder, ReminderTemplate,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,6 +131,135 @@ pub async fn get_guild_roles(id: u64, cookies: &CookieJar<'_>, ctx: &State<Conte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/api/guild/<id>/templates")]
|
||||||
|
pub async fn get_reminder_templates(
|
||||||
|
id: u64,
|
||||||
|
cookies: &CookieJar<'_>,
|
||||||
|
ctx: &State<Context>,
|
||||||
|
pool: &State<Pool<MySql>>,
|
||||||
|
) -> JsonValue {
|
||||||
|
check_authorization!(cookies, ctx.inner(), id);
|
||||||
|
|
||||||
|
match sqlx::query_as_unchecked!(
|
||||||
|
ReminderTemplate,
|
||||||
|
"SELECT * FROM reminder_template WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)",
|
||||||
|
id
|
||||||
|
)
|
||||||
|
.fetch_all(pool.inner())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(templates) => {
|
||||||
|
json!(templates)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Could not fetch templates from {}: {:?}", id, e);
|
||||||
|
|
||||||
|
json!({"error": "Could not get templates"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/api/guild/<id>/templates", data = "<reminder_template>")]
|
||||||
|
pub async fn create_reminder_template(
|
||||||
|
id: u64,
|
||||||
|
reminder_template: Json<ReminderTemplate>,
|
||||||
|
cookies: &CookieJar<'_>,
|
||||||
|
ctx: &State<Context>,
|
||||||
|
pool: &State<Pool<MySql>>,
|
||||||
|
) -> JsonValue {
|
||||||
|
check_authorization!(cookies, ctx.inner(), id);
|
||||||
|
|
||||||
|
// validate lengths
|
||||||
|
check_length!(MAX_CONTENT_LENGTH, reminder_template.content);
|
||||||
|
check_length!(MAX_EMBED_DESCRIPTION_LENGTH, reminder_template.embed_description);
|
||||||
|
check_length!(MAX_EMBED_TITLE_LENGTH, reminder_template.embed_title);
|
||||||
|
check_length!(MAX_EMBED_AUTHOR_LENGTH, reminder_template.embed_author);
|
||||||
|
check_length!(MAX_EMBED_FOOTER_LENGTH, reminder_template.embed_footer);
|
||||||
|
check_length_opt!(MAX_EMBED_FIELDS, reminder_template.embed_fields);
|
||||||
|
if let Some(fields) = &reminder_template.embed_fields {
|
||||||
|
for field in &fields.0 {
|
||||||
|
check_length!(MAX_EMBED_FIELD_VALUE_LENGTH, field.value);
|
||||||
|
check_length!(MAX_EMBED_FIELD_TITLE_LENGTH, field.title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_length_opt!(MAX_USERNAME_LENGTH, reminder_template.username);
|
||||||
|
check_length_opt!(
|
||||||
|
MAX_URL_LENGTH,
|
||||||
|
reminder_template.embed_footer_url,
|
||||||
|
reminder_template.embed_thumbnail_url,
|
||||||
|
reminder_template.embed_author_url,
|
||||||
|
reminder_template.embed_image_url,
|
||||||
|
reminder_template.avatar
|
||||||
|
);
|
||||||
|
|
||||||
|
// validate urls
|
||||||
|
check_url_opt!(
|
||||||
|
reminder_template.embed_footer_url,
|
||||||
|
reminder_template.embed_thumbnail_url,
|
||||||
|
reminder_template.embed_author_url,
|
||||||
|
reminder_template.embed_image_url,
|
||||||
|
reminder_template.avatar
|
||||||
|
);
|
||||||
|
|
||||||
|
let name = if reminder_template.name.is_empty() {
|
||||||
|
template_name_default()
|
||||||
|
} else {
|
||||||
|
reminder_template.name.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
match sqlx::query!(
|
||||||
|
"INSERT INTO reminder_template
|
||||||
|
(guild_id,
|
||||||
|
name,
|
||||||
|
attachment,
|
||||||
|
attachment_name,
|
||||||
|
avatar,
|
||||||
|
content,
|
||||||
|
embed_author,
|
||||||
|
embed_author_url,
|
||||||
|
embed_color,
|
||||||
|
embed_description,
|
||||||
|
embed_footer,
|
||||||
|
embed_footer_url,
|
||||||
|
embed_image_url,
|
||||||
|
embed_thumbnail_url,
|
||||||
|
embed_title,
|
||||||
|
embed_fields,
|
||||||
|
tts,
|
||||||
|
username
|
||||||
|
) VALUES ((SELECT id FROM guilds WHERE guild = ?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
id, name,
|
||||||
|
reminder_template.attachment,
|
||||||
|
reminder_template.attachment_name,
|
||||||
|
reminder_template.avatar,
|
||||||
|
reminder_template.content,
|
||||||
|
reminder_template.embed_author,
|
||||||
|
reminder_template.embed_author_url,
|
||||||
|
reminder_template.embed_color,
|
||||||
|
reminder_template.embed_description,
|
||||||
|
reminder_template.embed_footer,
|
||||||
|
reminder_template.embed_footer_url,
|
||||||
|
reminder_template.embed_image_url,
|
||||||
|
reminder_template.embed_thumbnail_url,
|
||||||
|
reminder_template.embed_title,
|
||||||
|
reminder_template.embed_fields,
|
||||||
|
reminder_template.tts,
|
||||||
|
reminder_template.username,
|
||||||
|
)
|
||||||
|
.fetch_all(pool.inner())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {
|
||||||
|
json!({})
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Could not fetch templates from {}: {:?}", id, e);
|
||||||
|
|
||||||
|
json!({"error": "Could not get templates"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[post("/api/guild/<id>/reminders", data = "<reminder>")]
|
#[post("/api/guild/<id>/reminders", data = "<reminder>")]
|
||||||
pub async fn create_reminder(
|
pub async fn create_reminder(
|
||||||
id: u64,
|
id: u64,
|
||||||
@ -550,9 +679,8 @@ pub async fn edit_reminder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[delete("/api/guild/<id>/reminders", data = "<reminder>")]
|
#[delete("/api/guild/<_>/reminders", data = "<reminder>")]
|
||||||
pub async fn delete_reminder(
|
pub async fn delete_reminder(
|
||||||
id: u64,
|
|
||||||
reminder: Json<DeleteReminder>,
|
reminder: Json<DeleteReminder>,
|
||||||
pool: &State<Pool<MySql>>,
|
pool: &State<Pool<MySql>>,
|
||||||
) -> JsonValue {
|
) -> JsonValue {
|
||||||
|
@ -22,10 +22,44 @@ fn name_default() -> String {
|
|||||||
"Reminder".to_string()
|
"Reminder".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn template_name_default() -> String {
|
||||||
|
"Template".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn channel_default() -> u64 {
|
fn channel_default() -> u64 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn id_default() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ReminderTemplate {
|
||||||
|
#[serde(default = "id_default")]
|
||||||
|
id: u32,
|
||||||
|
#[serde(default = "id_default")]
|
||||||
|
guild_id: u32,
|
||||||
|
#[serde(default = "template_name_default")]
|
||||||
|
name: String,
|
||||||
|
attachment: Option<Vec<u8>>,
|
||||||
|
attachment_name: Option<String>,
|
||||||
|
avatar: Option<String>,
|
||||||
|
content: String,
|
||||||
|
embed_author: String,
|
||||||
|
embed_author_url: Option<String>,
|
||||||
|
embed_color: u32,
|
||||||
|
embed_description: String,
|
||||||
|
embed_footer: String,
|
||||||
|
embed_footer_url: Option<String>,
|
||||||
|
embed_image_url: Option<String>,
|
||||||
|
embed_thumbnail_url: Option<String>,
|
||||||
|
embed_title: String,
|
||||||
|
embed_fields: Option<Json<Vec<EmbedField>>>,
|
||||||
|
tts: bool,
|
||||||
|
username: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct EmbedField {
|
pub struct EmbedField {
|
||||||
title: String,
|
title: String,
|
||||||
@ -241,3 +275,13 @@ pub async fn dashboard_home(cookies: &CookieJar<'_>) -> Result<Template, Redirec
|
|||||||
Err(Redirect::to("/login/discord"))
|
Err(Redirect::to("/login/discord"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/<_>")]
|
||||||
|
pub async fn dashboard(cookies: &CookieJar<'_>) -> Result<Template, Redirect> {
|
||||||
|
if cookies.get_private("userid").is_some() {
|
||||||
|
let map: HashMap<&str, String> = HashMap::new();
|
||||||
|
Ok(Template::render("dashboard", &map))
|
||||||
|
} else {
|
||||||
|
Err(Redirect::to("/login/discord"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,52 +3,61 @@
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKwdSBYKcSV-LCoeQqfX1RYOo3qPZZMkids18E.ttf) format('truetype');
|
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKwdSBYKcSV-LCoeQqfX1RYOo3qPZZMkids18E.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Source Sans Pro';
|
font-family: 'Source Sans Pro';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7nsDc.ttf) format('truetype');
|
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7nsDc.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Source Sans Pro';
|
font-family: 'Source Sans Pro';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKwdSBYKcSV-LCoeQqfX1RYOo3qPZY4lCds18E.ttf) format('truetype');
|
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKwdSBYKcSV-LCoeQqfX1RYOo3qPZY4lCds18E.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Source Sans Pro';
|
font-family: 'Source Sans Pro';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlxdr.ttf) format('truetype');
|
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlxdr.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Source Sans Pro';
|
font-family: 'Source Sans Pro';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7g.ttf) format('truetype');
|
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7g.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Source Sans Pro';
|
font-family: 'Source Sans Pro';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdr.ttf) format('truetype');
|
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdr.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Source Sans Pro';
|
font-family: 'Source Sans Pro';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdr.ttf) format('truetype');
|
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdr.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: url(https://fonts.gstatic.com/s/ubuntu/v15/4iCs6KVjbNBYlgo6eA.ttf) format('truetype');
|
src: url(https://fonts.gstatic.com/s/ubuntu/v15/4iCs6KVjbNBYlgo6eA.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src: url(https://fonts.gstatic.com/s/ubuntu/v15/4iCv6KVjbNBYlgoCxCvTtw.ttf) format('truetype');
|
src: url(https://fonts.gstatic.com/s/ubuntu/v15/4iCv6KVjbNBYlgoCxCvTtw.ttf) format('truetype');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
font-family: "Ubuntu Bold", "Ubuntu", sans-serif;
|
font-family: "Ubuntu Bold", "Ubuntu", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
/* override styles for when the div is collapsed */
|
/* override styles for when the div is collapsed */
|
||||||
div.reminderContent.is-collapsed .column.discord-frame {
|
div.reminderContent.is-collapsed .column.discord-frame {
|
||||||
display: none;
|
display: none;
|
||||||
@ -55,6 +59,11 @@ div.reminderContent.is-collapsed button.hide-box i {
|
|||||||
/* END */
|
/* END */
|
||||||
|
|
||||||
/* dashboard styles */
|
/* dashboard styles */
|
||||||
|
button.inline-btn {
|
||||||
|
height: 100%;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
button.change-color {
|
button.change-color {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: calc(-1rem - 40px);
|
left: calc(-1rem - 40px);
|
||||||
@ -88,7 +97,7 @@ div.interval-group > button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Interval inputs */
|
/* Interval inputs */
|
||||||
div.interval-group > .interval-group-left > input {
|
div.interval-group > .interval-group-left input {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
border-style: none;
|
border-style: none;
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
@ -96,11 +105,11 @@ div.interval-group > .interval-group-left > input {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.interval-group > .interval-group-left > input.w2 {
|
div.interval-group > .interval-group-left input.w2 {
|
||||||
width: 3ch;
|
width: 3ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.interval-group > .interval-group-left > input.w3 {
|
div.interval-group > .interval-group-left input.w3 {
|
||||||
width: 6ch;
|
width: 6ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +162,15 @@ span.patreon-color {
|
|||||||
color: #f96854;
|
color: #f96854;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.pageTitle {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#welcome > div {
|
||||||
|
height: 100%;
|
||||||
|
padding-top: 30vh;
|
||||||
|
}
|
||||||
|
|
||||||
div#pageNavbar {
|
div#pageNavbar {
|
||||||
background-color: #363636;
|
background-color: #363636;
|
||||||
}
|
}
|
||||||
@ -188,6 +206,17 @@ div.dashboard-sidebar {
|
|||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.dashboard-sidebar:not(.mobile-sidebar) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dashboard-sidebar:not(.mobile-sidebar) .aside-footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 226px;
|
||||||
|
}
|
||||||
|
|
||||||
div.mobile-sidebar {
|
div.mobile-sidebar {
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
@ -197,10 +226,24 @@ div.mobile-sidebar {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#expandAll {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mobile-sidebar .aside-footer {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
div.mobile-sidebar.is-active {
|
div.mobile-sidebar.is-active {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aside.menu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
div.dashboard-frame {
|
div.dashboard-frame {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
@ -475,3 +518,40 @@ textarea, input {
|
|||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* loader */
|
||||||
|
#loader {
|
||||||
|
position: fixed;
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
width: 100vw;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader .title {
|
||||||
|
font-size: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* END */
|
||||||
|
|
||||||
|
/* other stuff */
|
||||||
|
|
||||||
|
.half-rem {
|
||||||
|
width: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pad-left {
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorpicker-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-reminder {
|
||||||
|
margin: 0 12px 12px 12px;
|
||||||
|
}
|
||||||
|
@ -6,9 +6,19 @@ const $colorPickerInput = $colorPickerModal.querySelector("input");
|
|||||||
const $deleteReminderBtn = document.querySelector("#delete-reminder-confirm");
|
const $deleteReminderBtn = document.querySelector("#delete-reminder-confirm");
|
||||||
const $reminderTemplate = document.querySelector("template#guildReminder");
|
const $reminderTemplate = document.querySelector("template#guildReminder");
|
||||||
const $embedFieldTemplate = document.querySelector("template#embedFieldTemplate");
|
const $embedFieldTemplate = document.querySelector("template#embedFieldTemplate");
|
||||||
|
const $createReminder = document.querySelector("#reminderCreator");
|
||||||
|
const $createReminderBtn = $createReminder.querySelector("button#createReminder");
|
||||||
|
const $createTemplateBtn = $createReminder.querySelector("button#createTemplate");
|
||||||
|
const $loadTemplateBtn = document.querySelector("button#load-template");
|
||||||
|
const $templateSelect = document.querySelector("select#templateSelect");
|
||||||
|
|
||||||
let channels;
|
let channels = [];
|
||||||
let roles;
|
let roles = [];
|
||||||
|
let templates = {};
|
||||||
|
|
||||||
|
function guildId() {
|
||||||
|
return document.querySelector(".guildList a.is-active").dataset["guild"];
|
||||||
|
}
|
||||||
|
|
||||||
function colorToInt(r, g, b) {
|
function colorToInt(r, g, b) {
|
||||||
return (r << 16) + (g << 8) + b;
|
return (r << 16) + (g << 8) + b;
|
||||||
@ -77,6 +87,30 @@ function fetch_roles(guild_id) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetch_templates(guild_id) {
|
||||||
|
fetch(`/dashboard/api/guild/${guild_id}/templates`)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
show_error(data.error);
|
||||||
|
} else {
|
||||||
|
templates = {};
|
||||||
|
|
||||||
|
const select = document.querySelector("#templateSelect");
|
||||||
|
select.innerHTML = "";
|
||||||
|
for (let template of data) {
|
||||||
|
templates[template["id"]] = template;
|
||||||
|
|
||||||
|
let option = document.createElement("option");
|
||||||
|
option.value = template["id"];
|
||||||
|
option.textContent = template["name"];
|
||||||
|
|
||||||
|
select.appendChild(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function fetch_channels(guild_id) {
|
async function fetch_channels(guild_id) {
|
||||||
const event = new Event("channelsLoading");
|
const event = new Event("channelsLoading");
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
@ -121,7 +155,7 @@ async function fetch_reminders(guild_id) {
|
|||||||
newFrame.querySelector(".reminderContent").dataset["uid"] =
|
newFrame.querySelector(".reminderContent").dataset["uid"] =
|
||||||
reminder["uid"];
|
reminder["uid"];
|
||||||
|
|
||||||
deserialize_reminder(reminder, newFrame);
|
deserialize_reminder(reminder, newFrame, "load");
|
||||||
|
|
||||||
$reminderBox.appendChild(newFrame);
|
$reminderBox.appendChild(newFrame);
|
||||||
|
|
||||||
@ -137,8 +171,21 @@ async function fetch_reminders(guild_id) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function serialize_reminder(node) {
|
async function serialize_reminder(node, mode) {
|
||||||
let interval = get_interval(node);
|
let interval, utc_time;
|
||||||
|
|
||||||
|
if (mode !== "template") {
|
||||||
|
interval = get_interval(node);
|
||||||
|
|
||||||
|
utc_time = luxon.DateTime.fromISO(
|
||||||
|
node.querySelector('input[name="time"]').value
|
||||||
|
).setZone("UTC");
|
||||||
|
if (utc_time.invalid) {
|
||||||
|
return { error: "Time provided invalid." };
|
||||||
|
} else {
|
||||||
|
utc_time = utc_time.toFormat("yyyy-LL-dd'T'HH:mm:ss");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let rgb_color = window.getComputedStyle(
|
let rgb_color = window.getComputedStyle(
|
||||||
node.querySelector("div.discord-embed")
|
node.querySelector("div.discord-embed")
|
||||||
@ -146,21 +193,13 @@ async function serialize_reminder(node) {
|
|||||||
let rgb = rgb_color.match(/\d+/g);
|
let rgb = rgb_color.match(/\d+/g);
|
||||||
let color = colorToInt(parseInt(rgb[0]), parseInt(rgb[1]), parseInt(rgb[2]));
|
let color = colorToInt(parseInt(rgb[0]), parseInt(rgb[1]), parseInt(rgb[2]));
|
||||||
|
|
||||||
let utc_time = luxon.DateTime.fromISO(
|
|
||||||
node.querySelector('input[name="time"]').value
|
|
||||||
).setZone("UTC");
|
|
||||||
|
|
||||||
if (utc_time.invalid) {
|
|
||||||
return { error: "Time provided invalid." };
|
|
||||||
}
|
|
||||||
|
|
||||||
let fields = [
|
let fields = [
|
||||||
...node.querySelectorAll("div.embed-multifield-box div.embed-field-box"),
|
...node.querySelectorAll("div.embed-multifield-box div.embed-field-box"),
|
||||||
]
|
]
|
||||||
.map((el) => {
|
.map((el) => {
|
||||||
return {
|
return {
|
||||||
title: el.querySelector("textarea#embedFieldTitle").value,
|
title: el.querySelector("textarea.discord-field-title").value,
|
||||||
value: el.querySelector("textarea#embedFieldValue").value,
|
value: el.querySelector("textarea.discord-field-value").value,
|
||||||
inline: el.dataset["inlined"] === "1",
|
inline: el.dataset["inlined"] === "1",
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@ -181,13 +220,21 @@ async function serialize_reminder(node) {
|
|||||||
attachment_name = file.name;
|
attachment_name = file.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reminderContent = node.closest(".reminderContent");
|
let uid = "";
|
||||||
|
if (mode === "edit") {
|
||||||
|
uid = node.closest(".reminderContent").dataset["uid"];
|
||||||
|
}
|
||||||
|
|
||||||
|
let enabled = null;
|
||||||
|
if (mode === "create") {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// if we're creating a reminder, ignore this field
|
// if we're creating a reminder, ignore this field
|
||||||
uid: reminderContent !== null ? reminderContent.dataset["uid"] : "",
|
uid: uid,
|
||||||
// if we're editing a reminder, ignore this field
|
// if we're editing a reminder, ignore this field
|
||||||
enabled: reminderContent !== null ? null : true,
|
enabled: enabled,
|
||||||
restartable: false,
|
restartable: false,
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
attachment_name: attachment_name,
|
attachment_name: attachment_name,
|
||||||
@ -207,17 +254,17 @@ async function serialize_reminder(node) {
|
|||||||
embed_title: node.querySelector('textarea[name="embed_title"]').value,
|
embed_title: node.querySelector('textarea[name="embed_title"]').value,
|
||||||
embed_fields: fields,
|
embed_fields: fields,
|
||||||
expires: null,
|
expires: null,
|
||||||
interval_seconds: interval.seconds,
|
interval_seconds: mode !== "template" ? interval.seconds : null,
|
||||||
interval_months: interval.months,
|
interval_months: mode !== "template" ? interval.months : null,
|
||||||
name: node.querySelector('input[name="name"]').value,
|
name: node.querySelector('input[name="name"]').value,
|
||||||
pin: node.querySelector('input[name="pin"]').checked,
|
pin: node.querySelector('input[name="pin"]').checked,
|
||||||
tts: node.querySelector('input[name="tts"]').checked,
|
tts: node.querySelector('input[name="tts"]').checked,
|
||||||
username: node.querySelector('input[name="username"]').value,
|
username: node.querySelector('input[name="username"]').value,
|
||||||
utc_time: utc_time.toFormat("yyyy-LL-dd'T'HH:mm:ss"),
|
utc_time: utc_time,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function deserialize_reminder(reminder, frame) {
|
function deserialize_reminder(reminder, frame, mode) {
|
||||||
// populate channels
|
// populate channels
|
||||||
set_channels(frame.querySelector("select.channel-selector"));
|
set_channels(frame.querySelector("select.channel-selector"));
|
||||||
|
|
||||||
@ -256,16 +303,18 @@ function deserialize_reminder(reminder, frame) {
|
|||||||
.insertBefore(embed_field, lastChild);
|
.insertBefore(embed_field, lastChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reminder["interval_seconds"] !== null) update_interval(frame);
|
if (mode !== "template") {
|
||||||
|
if (reminder["interval_seconds"]) update_interval(frame);
|
||||||
|
|
||||||
let $enableBtn = frame.querySelector(".disable-enable");
|
let $enableBtn = frame.querySelector(".disable-enable");
|
||||||
$enableBtn.dataset["action"] = reminder["enabled"] ? "disable" : "enable";
|
$enableBtn.dataset["action"] = reminder["enabled"] ? "disable" : "enable";
|
||||||
|
|
||||||
let timeInput = frame.querySelector('input[name="time"]');
|
let timeInput = frame.querySelector('input[name="time"]');
|
||||||
let localTime = luxon.DateTime.fromISO(reminder["utc_time"], { zone: "UTC" }).setZone(
|
let localTime = luxon.DateTime.fromISO(reminder["utc_time"], {
|
||||||
timezone
|
zone: "UTC",
|
||||||
);
|
}).setZone(timezone);
|
||||||
timeInput.value = localTime.toFormat("yyyy-LL-dd'T'HH:mm:ss");
|
timeInput.value = localTime.toFormat("yyyy-LL-dd'T'HH:mm:ss");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("guildSwitched", async (e) => {
|
document.addEventListener("guildSwitched", async (e) => {
|
||||||
@ -276,11 +325,11 @@ document.addEventListener("guildSwitched", async (e) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
switch_pane($anchor.dataset["pane"]);
|
switch_pane($anchor.dataset["pane"]);
|
||||||
|
reset_guild_pane();
|
||||||
$anchor.classList.add("is-active");
|
$anchor.classList.add("is-active");
|
||||||
|
|
||||||
reset_guild_pane();
|
|
||||||
|
|
||||||
fetch_roles(e.detail.guild_id);
|
fetch_roles(e.detail.guild_id);
|
||||||
|
fetch_templates(e.detail.guild_id);
|
||||||
await fetch_channels(e.detail.guild_id);
|
await fetch_channels(e.detail.guild_id);
|
||||||
fetch_reminders(e.detail.guild_id);
|
fetch_reminders(e.detail.guild_id);
|
||||||
|
|
||||||
@ -303,7 +352,7 @@ document.addEventListener("channelsLoaded", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("remindersLoaded", (event) => {
|
document.addEventListener("remindersLoaded", (event) => {
|
||||||
const guild = document.querySelector(".guildList a.is-active").dataset["guild"];
|
const guild = guildId();
|
||||||
|
|
||||||
for (let reminder of event.detail) {
|
for (let reminder of event.detail) {
|
||||||
let node = reminder.node;
|
let node = reminder.node;
|
||||||
@ -351,13 +400,13 @@ document.addEventListener("remindersLoaded", (event) => {
|
|||||||
"fas fa-spinner fa-spin",
|
"fas fa-spinner fa-spin",
|
||||||
];
|
];
|
||||||
|
|
||||||
let reminder = await serialize_reminder(node);
|
let reminder = await serialize_reminder(node, "edit");
|
||||||
if (reminder.error) {
|
if (reminder.error) {
|
||||||
show_error(reminder.error);
|
show_error(reminder.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let guild = document.querySelector(".guildList a.is-active").dataset["guild"];
|
let guild = guildId();
|
||||||
|
|
||||||
fetch(`/dashboard/api/guild/${guild}/reminders`, {
|
fetch(`/dashboard/api/guild/${guild}/reminders`, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
@ -381,7 +430,7 @@ document.addEventListener("remindersLoaded", (event) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$deleteReminderBtn.addEventListener("click", () => {
|
$deleteReminderBtn.addEventListener("click", () => {
|
||||||
let guild = document.querySelector(".guildList a.is-active").dataset["guild"];
|
let guild = guildId();
|
||||||
|
|
||||||
fetch(`/dashboard/api/guild/${guild}/reminders`, {
|
fetch(`/dashboard/api/guild/${guild}/reminders`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
@ -422,7 +471,7 @@ $colorPickerModal.querySelector("button.is-success").addEventListener("click", (
|
|||||||
$colorPickerModal.classList.remove("is-active");
|
$colorPickerModal.classList.remove("is-active");
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll("a.show-modal").forEach((element) => {
|
document.querySelectorAll(".show-modal").forEach((element) => {
|
||||||
element.addEventListener("click", (e) => {
|
element.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
document.getElementById(element.dataset["modal"]).classList.toggle("is-active");
|
document.getElementById(element.dataset["modal"]).classList.toggle("is-active");
|
||||||
@ -480,10 +529,15 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
);
|
);
|
||||||
$anchor.dataset["guild"] = guild.id;
|
$anchor.dataset["guild"] = guild.id;
|
||||||
$anchor.dataset["name"] = guild.name;
|
$anchor.dataset["name"] = guild.name;
|
||||||
|
$anchor.href = `/dashboard/${guild.id}?name=${guild.name}`;
|
||||||
|
|
||||||
$anchor.addEventListener("click", async (e) => {
|
$anchor.addEventListener("click", async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
window.history.pushState(
|
||||||
|
{},
|
||||||
|
"",
|
||||||
|
`/dashboard/${guild.id}?name=${guild.name}`
|
||||||
|
);
|
||||||
const event = new CustomEvent("guildSwitched", {
|
const event = new CustomEvent("guildSwitched", {
|
||||||
detail: {
|
detail: {
|
||||||
guild_name: guild.name,
|
guild_name: guild.name,
|
||||||
@ -497,6 +551,21 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
element.append($clone);
|
element.append($clone);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const matches = window.location.href.match(/dashboard\/(\d+)/);
|
||||||
|
if (matches) {
|
||||||
|
let id = matches[1];
|
||||||
|
let name =
|
||||||
|
new URLSearchParams(window.location.search).get("name") || id;
|
||||||
|
const event = new CustomEvent("guildSwitched", {
|
||||||
|
detail: {
|
||||||
|
guild_name: name,
|
||||||
|
guild_id: id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -530,34 +599,18 @@ function has_source(string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let $createReminder = document.querySelector("#reminderCreator");
|
$createReminderBtn.addEventListener("click", async () => {
|
||||||
let $createBtn = $createReminder.querySelector("button#createReminder");
|
$createReminderBtn.querySelector("span.icon > i").classList = [
|
||||||
|
"fas fa-spinner fa-spin",
|
||||||
|
];
|
||||||
|
|
||||||
$createBtn.addEventListener("click", async () => {
|
let reminder = await serialize_reminder($createReminder, "create");
|
||||||
$createBtn.querySelector("span.icon > i").classList = ["fas fa-spinner fa-spin"];
|
|
||||||
|
|
||||||
let attachment = null;
|
|
||||||
let attachment_name = null;
|
|
||||||
|
|
||||||
if ($createReminder.querySelector('input[name="attachment"]').files.length > 0) {
|
|
||||||
let file = $createReminder.querySelector('input[name="attachment"]').files[0];
|
|
||||||
|
|
||||||
attachment = await new Promise((resolve) => {
|
|
||||||
let fileReader = new FileReader();
|
|
||||||
fileReader.onload = (e) => resolve(fileReader.result);
|
|
||||||
fileReader.readAsDataURL(file);
|
|
||||||
});
|
|
||||||
attachment = attachment.split(",")[1];
|
|
||||||
attachment_name = file.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
let reminder = await serialize_reminder($createReminder);
|
|
||||||
if (reminder.error) {
|
if (reminder.error) {
|
||||||
show_error(reminder.error);
|
show_error(reminder.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let guild = document.querySelector(".guildList a.is-active").dataset["guild"];
|
let guild = guildId();
|
||||||
|
|
||||||
fetch(`/dashboard/api/guild/${guild}/reminders`, {
|
fetch(`/dashboard/api/guild/${guild}/reminders`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@ -570,13 +623,17 @@ $createBtn.addEventListener("click", async () => {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
show_error(data.error);
|
show_error(data.error);
|
||||||
|
|
||||||
|
$createReminderBtn.querySelector("span.icon > i").classList = [
|
||||||
|
"fas fa-sparkles",
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
const $reminderBox = document.querySelector("div#guildReminders");
|
const $reminderBox = document.querySelector("div#guildReminders");
|
||||||
let newFrame = $reminderTemplate.content.cloneNode(true);
|
let newFrame = $reminderTemplate.content.cloneNode(true);
|
||||||
|
|
||||||
newFrame.querySelector(".reminderContent").dataset["uid"] = data["uid"];
|
newFrame.querySelector(".reminderContent").dataset["uid"] = data["uid"];
|
||||||
|
|
||||||
deserialize_reminder(data, newFrame);
|
deserialize_reminder(data, newFrame, "load");
|
||||||
|
|
||||||
$reminderBox.appendChild(newFrame);
|
$reminderBox.appendChild(newFrame);
|
||||||
|
|
||||||
@ -587,16 +644,62 @@ $createBtn.addEventListener("click", async () => {
|
|||||||
detail: [data],
|
detail: [data],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
$createBtn.querySelector("span.icon > i").classList = ["fas fa-check"];
|
$createReminderBtn.querySelector("span.icon > i").classList = [
|
||||||
|
"fas fa-check",
|
||||||
|
];
|
||||||
|
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
$createBtn.querySelector("span.icon > i").classList = ["fas fa-sparkles"];
|
$createReminderBtn.querySelector("span.icon > i").classList = [
|
||||||
|
"fas fa-sparkles",
|
||||||
|
];
|
||||||
}, 1500);
|
}, 1500);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$createTemplateBtn.addEventListener("click", async () => {
|
||||||
|
let reminder = await serialize_reminder($createReminder, "template");
|
||||||
|
let guild = guildId();
|
||||||
|
|
||||||
|
fetch(`/dashboard/api/guild/${guild}/templates`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(reminder),
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
show_error(data.error);
|
||||||
|
$createTemplateBtn.querySelector("span.icon > i").classList = [
|
||||||
|
"fas fa-file-spreadsheet",
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
fetch_templates(guildId());
|
||||||
|
|
||||||
|
$createTemplateBtn.querySelector("span.icon > i").classList = [
|
||||||
|
"fas fa-check",
|
||||||
|
];
|
||||||
|
|
||||||
|
window.setTimeout(() => {
|
||||||
|
$createTemplateBtn.querySelector("span.icon > i").classList = [
|
||||||
|
"fas fa-file-spreadsheet",
|
||||||
|
];
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$loadTemplateBtn.addEventListener("click", (ev) => {
|
||||||
|
deserialize_reminder(
|
||||||
|
templates[parseInt($templateSelect.value)],
|
||||||
|
$createReminder,
|
||||||
|
"template"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
document.querySelectorAll("textarea.autoresize").forEach((element) => {
|
document.querySelectorAll("textarea.autoresize").forEach((element) => {
|
||||||
element.addEventListener("input", () => {
|
element.addEventListener("input", () => {
|
||||||
element.style.height = "";
|
element.style.height = "";
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="yandex-verification" content="bb77b8681eb64a90"/>
|
<meta name="yandex-verification" content="bb77b8681eb64a90"/>
|
||||||
<meta name="google-site-verification" content="7h7UVTeEe0AOzHiH3cFtsqMULYGN-zCZdMT_YCkW1Ho"/>
|
<meta name="google-site-verification" content="7h7UVTeEe0AOzHiH3cFtsqMULYGN-zCZdMT_YCkW1Ho"/>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src *; font-src fonts.gstatic.com 'self'">
|
||||||
|
|
||||||
<!-- favicon -->
|
<!-- favicon -->
|
||||||
<link rel="apple-touch-icon" sizes="180x180"
|
<link rel="apple-touch-icon" sizes="180x180"
|
||||||
@ -27,10 +28,7 @@
|
|||||||
<link rel="stylesheet" href="/static/css/style.css">
|
<link rel="stylesheet" href="/static/css/style.css">
|
||||||
<link rel="stylesheet" href="/static/css/dtsel.css">
|
<link rel="stylesheet" href="/static/css/dtsel.css">
|
||||||
|
|
||||||
<script src="/static/js/iro.js"></script>
|
|
||||||
<script src="/static/js/dtsel.js"></script>
|
|
||||||
<script src="/static/js/luxon.min.js"></script>
|
<script src="/static/js/luxon.min.js"></script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar is-spaced is-size-4 is-hidden-desktop dashboard-navbar" role="navigation"
|
<nav class="navbar is-spaced is-size-4 is-hidden-desktop dashboard-navbar" role="navigation"
|
||||||
@ -54,10 +52,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="loader" class="is-hidden hero is-fullheight" style="position: fixed; background-color: rgba(255, 255, 255, 0.8); width: 100vw; z-index: 999;">
|
<div id="loader" class="is-hidden hero is-fullheight">
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container has-text-centered">
|
<div class="container has-text-centered">
|
||||||
<p class="title" style="font-size: 6rem; color: #8fb677">
|
<p class="title">
|
||||||
<i class="fas fa-cog fa-spin"></i>
|
<i class="fas fa-cog fa-spin"></i>
|
||||||
</p>
|
</p>
|
||||||
<p class="subtitle">
|
<p class="subtitle">
|
||||||
@ -68,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- dead image used to check which other images are dead -->
|
<!-- dead image used to check which other images are dead -->
|
||||||
<img style="display: none;" src="" id="dead">
|
<img src="" id="dead">
|
||||||
|
|
||||||
<div class="notification is-danger flash-message" id="errors">
|
<div class="notification is-danger flash-message" id="errors">
|
||||||
<span class="icon"><i class="far fa-exclamation-circle"></i></span> <span class="error-message"></span>
|
<span class="icon"><i class="far fa-exclamation-circle"></i></span> <span class="error-message"></span>
|
||||||
@ -100,7 +98,7 @@
|
|||||||
<button class="delete close-modal" aria-label="close"></button>
|
<button class="delete close-modal" aria-label="close"></button>
|
||||||
</header>
|
</header>
|
||||||
<section class="modal-card-body">
|
<section class="modal-card-body">
|
||||||
<div style="display: flex; justify-content: center">
|
<div class="colorpicker-container">
|
||||||
<div id="colorpicker"></div>
|
<div id="colorpicker"></div>
|
||||||
</div>
|
</div>
|
||||||
<input class="input" id="colorInput">
|
<input class="input" id="colorInput">
|
||||||
@ -140,6 +138,33 @@
|
|||||||
<button class="modal-close is-large close-modal" aria-label="close"></button>
|
<button class="modal-close is-large close-modal" aria-label="close"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal" id="chooseTemplateModal">
|
||||||
|
<div class="modal-background"></div>
|
||||||
|
<div class="modal-card">
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<label class="modal-card-title" for="urlInput">Load Template</label>
|
||||||
|
<button class="delete close-modal" aria-label="close"></button>
|
||||||
|
</header>
|
||||||
|
<section class="modal-card-body">
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<div class="select is-fullwidth">
|
||||||
|
<select id="templateSelect">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="icon is-small is-left">
|
||||||
|
<i class="fas fa-file-spreadsheet"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="has-text-centered">
|
||||||
|
<button class="button is-success close-modal" id="load-template">Load Template</button>
|
||||||
|
<button class="button is-danger" id="delete-template">Delete</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<button class="modal-close is-large close-modal" aria-label="close"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal" id="dataManagerModal">
|
<div class="modal" id="dataManagerModal">
|
||||||
<div class="modal-background"></div>
|
<div class="modal-background"></div>
|
||||||
<div class="modal-card">
|
<div class="modal-card">
|
||||||
@ -179,7 +204,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="columns is-gapless dashboard-frame">
|
<div class="columns is-gapless dashboard-frame">
|
||||||
<div class="column is-2 is-sidebar-menu dashboard-sidebar is-hidden-touch" style="display: flex; flex-direction: column;">
|
<div class="column is-2 is-sidebar-menu dashboard-sidebar is-hidden-touch">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<div class="brand">
|
<div class="brand">
|
||||||
<img src="/static/img/logo_flat.webp" alt="Reminder bot logo"
|
<img src="/static/img/logo_flat.webp" alt="Reminder bot logo"
|
||||||
@ -192,14 +217,14 @@
|
|||||||
d="M0,192L60,170.7C120,149,240,107,360,96C480,85,600,107,720,138.7C840,171,960,213,1080,197.3C1200,181,1320,107,1380,69.3L1440,32L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z"></path>
|
d="M0,192L60,170.7C120,149,240,107,360,96C480,85,600,107,720,138.7C840,171,960,213,1080,197.3C1200,181,1320,107,1380,69.3L1440,32L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z"></path>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
<aside class="menu" style="display: flex; flex-direction: column; flex-grow: 1;">
|
<aside class="menu">
|
||||||
<p class="menu-label">
|
<p class="menu-label">
|
||||||
Servers
|
Servers
|
||||||
</p>
|
</p>
|
||||||
<ul class="menu-list guildList">
|
<ul class="menu-list guildList">
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<div class="aside-footer" style="position: fixed; bottom: 0; width: 226px;">
|
<div class="aside-footer">
|
||||||
<p class="menu-label">
|
<p class="menu-label">
|
||||||
Settings
|
Settings
|
||||||
</p>
|
</p>
|
||||||
@ -230,14 +255,14 @@
|
|||||||
d="M0,192L60,170.7C120,149,240,107,360,96C480,85,600,107,720,138.7C840,171,960,213,1080,197.3C1200,181,1320,107,1380,69.3L1440,32L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z"></path>
|
d="M0,192L60,170.7C120,149,240,107,360,96C480,85,600,107,720,138.7C840,171,960,213,1080,197.3C1200,181,1320,107,1380,69.3L1440,32L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z"></path>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
<aside class="menu" style="display: flex; flex-direction: column; flex-grow: 1;">
|
<aside class="menu">
|
||||||
<p class="menu-label">
|
<p class="menu-label">
|
||||||
Servers
|
Servers
|
||||||
</p>
|
</p>
|
||||||
<ul class="menu-list guildList">
|
<ul class="menu-list guildList">
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<div class="aside-footer" style="margin-top: auto;">
|
<div class="aside-footer">
|
||||||
<p class="menu-label">
|
<p class="menu-label">
|
||||||
Settings
|
Settings
|
||||||
</p>
|
</p>
|
||||||
@ -257,17 +282,14 @@
|
|||||||
|
|
||||||
<!-- main content -->
|
<!-- main content -->
|
||||||
<div class="column is-main-content">
|
<div class="column is-main-content">
|
||||||
<p class="title pageTitle" style="margin-left: 12px;"></p>
|
<p class="title pageTitle"></p>
|
||||||
<section id="welcome">
|
<section id="welcome">
|
||||||
<div class="has-text-centered" style="height: 100%; padding-top: 30vh;">
|
<div class="has-text-centered">
|
||||||
<p class="title">Welcome!</p>
|
<p class="title">Welcome!</p>
|
||||||
<p class="subtitle is-hidden-touch">Select an option from the side to get started</p>
|
<p class="subtitle is-hidden-touch">Select an option from the side to get started</p>
|
||||||
<p class="subtitle is-hidden-desktop">Press the <span class="icon"><i class="fal fa-bars"></i></span> to get started</p>
|
<p class="subtitle is-hidden-desktop">Press the <span class="icon"><i class="fal fa-bars"></i></span> to get started</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section id="personal" class="is-hidden">
|
|
||||||
{% include "reminder_dashboard/reminder_dashboard_personal" %}
|
|
||||||
</section>
|
|
||||||
<section id="guild" class="is-hidden">
|
<section id="guild" class="is-hidden">
|
||||||
{% include "reminder_dashboard/reminder_dashboard" %}
|
{% include "reminder_dashboard/reminder_dashboard" %}
|
||||||
</section>
|
</section>
|
||||||
@ -294,20 +316,26 @@
|
|||||||
|
|
||||||
<template id="embedFieldTemplate">
|
<template id="embedFieldTemplate">
|
||||||
<div data-inlined="1" class="embed-field-box">
|
<div data-inlined="1" class="embed-field-box">
|
||||||
<label class="is-sr-only" for="embedFieldTitle">Field Title</label>
|
<div class="is-flex">
|
||||||
<div style="display: flex;">
|
<label>
|
||||||
|
<span class="is-sr-only">Field Title</span>
|
||||||
<textarea class="discord-field-title field-input message-input autoresize"
|
<textarea class="discord-field-title field-input message-input autoresize"
|
||||||
placeholder="Field Title..." rows="1"
|
placeholder="Field Title..." rows="1"
|
||||||
maxlength="256" id="embedFieldTitle" name="embed_field_title[]"></textarea>
|
maxlength="256" name="embed_field_title[]"></textarea>
|
||||||
<button class="button is-small inline-btn" style="height: 100%; padding: 5px;"><i class="fas fa-arrows-h"></i></button>
|
</label>
|
||||||
|
<button class="button is-small inline-btn">
|
||||||
|
<span class="is-sr-only">Toggle field inline</span><i class="fas fa-arrows-h"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label class="is-sr-only" for="embedFieldValue">Field Value</label>
|
<label>
|
||||||
|
<span class="is-sr-only">Field Value</span>
|
||||||
<textarea
|
<textarea
|
||||||
class="discord-field-value field-input message-input autoresize"
|
class="discord-field-value field-input message-input autoresize"
|
||||||
placeholder="Field Value..."
|
placeholder="Field Value..."
|
||||||
maxlength="1024" id="embedFieldValue" name="embed_field_value[]"
|
maxlength="1024" name="embed_field_value[]"
|
||||||
rows="1"></textarea>
|
rows="1"></textarea>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -323,13 +351,12 @@
|
|||||||
{% include "reminder_dashboard/guild_reminder" %}
|
{% include "reminder_dashboard/guild_reminder" %}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template id="personalReminder">
|
<script src="/static/js/iro.js"></script>
|
||||||
{% include "reminder_dashboard/personal_reminder" %}
|
<script src="/static/js/dtsel.js"></script>
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="/static/js/interval.js"></script>
|
<script src="/static/js/interval.js"></script>
|
||||||
<script src="/static/js/timezone.js"></script>
|
<script src="/static/js/timezone.js" defer></script>
|
||||||
<script src="/static/js/main.js"></script>
|
<script src="/static/js/main.js" defer></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -4,33 +4,33 @@
|
|||||||
<figure class="media-left">
|
<figure class="media-left">
|
||||||
<p class="image is-32x32 customizable">
|
<p class="image is-32x32 customizable">
|
||||||
<a>
|
<a>
|
||||||
<img class="is-rounded discord-avatar" src="/static/img/bg.webp">
|
<img class="is-rounded discord-avatar" src="/static/img/bg.webp" alt="Image for discord avatar">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</figure>
|
</figure>
|
||||||
<div class="media-content">
|
<div class="media-content">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="discord-message-header">
|
<div class="discord-message-header">
|
||||||
<label class="is-sr-only" for="reminderUsername">Username Override</label>
|
<label class="is-sr-only">Username Override</label>
|
||||||
<input class="discord-username message-input" placeholder="Username Override"
|
<input class="discord-username message-input" placeholder="Username Override"
|
||||||
maxlength="32" id="reminderUsername" name="username">
|
maxlength="32" name="username">
|
||||||
</div>
|
</div>
|
||||||
<label class="is-sr-only" for="messageContent">Message</label>
|
<label class="is-sr-only">Message</label>
|
||||||
<textarea class="message-input autoresize discord-content"
|
<textarea class="message-input autoresize discord-content"
|
||||||
placeholder="Message Content..."
|
placeholder="Message Content..."
|
||||||
maxlength="2000" id="messageContent" name="content" rows="1"></textarea>
|
maxlength="2000" name="content" rows="1"></textarea>
|
||||||
|
|
||||||
<div class="discord-embed">
|
<div class="discord-embed">
|
||||||
<div class="embed-body">
|
<div class="embed-body">
|
||||||
<button class="change-color button is-rounded is-small">
|
<button class="change-color button is-rounded is-small">
|
||||||
<i class="fas fa-eye-dropper"></i>
|
<span class="is-sr-only">Choose embed color</span><i class="fas fa-eye-dropper"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="a">
|
<div class="a">
|
||||||
<div class="embed-author-box">
|
<div class="embed-author-box">
|
||||||
<div class="a">
|
<div class="a">
|
||||||
<p class="image is-24x24 customizable">
|
<p class="image is-24x24 customizable">
|
||||||
<a>
|
<a>
|
||||||
<img class="is-rounded embed_author_url" src="/static/img/bg.webp">
|
<img class="is-rounded embed_author_url" src="/static/img/bg.webp" alt="Image for embed author">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -40,38 +40,40 @@
|
|||||||
<textarea
|
<textarea
|
||||||
class="discord-embed-author message-input autoresize"
|
class="discord-embed-author message-input autoresize"
|
||||||
placeholder="Embed Author..." rows="1" maxlength="256"
|
placeholder="Embed Author..." rows="1" maxlength="256"
|
||||||
id="embedAuthor" name="embed_author"></textarea>
|
name="embed_author"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label class="is-sr-only" for="embedTitle">Embed Title</label>
|
<label class="is-sr-only" for="embedTitle">Embed Title</label>
|
||||||
<textarea class="discord-title message-input autoresize"
|
<textarea class="discord-title message-input autoresize"
|
||||||
placeholder="Embed Title..."
|
placeholder="Embed Title..."
|
||||||
maxlength="256" id="embedTitle" rows="1"
|
maxlength="256" rows="1"
|
||||||
name="embed_title"></textarea>
|
name="embed_title"></textarea>
|
||||||
<br>
|
<br>
|
||||||
<label class="is-sr-only" for="embedDescription">Embed Description</label>
|
<label class="is-sr-only" for="embedDescription">Embed Description</label>
|
||||||
<textarea class="discord-description message-input autoresize "
|
<textarea class="discord-description message-input autoresize "
|
||||||
placeholder="Embed Description..."
|
placeholder="Embed Description..."
|
||||||
maxlength="4096" id="embedDescription" name="embed_description"
|
maxlength="4096" name="embed_description"
|
||||||
rows="1"></textarea>
|
rows="1"></textarea>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div class="embed-multifield-box">
|
<div class="embed-multifield-box">
|
||||||
<div data-inlined="1" class="embed-field-box">
|
<div data-inlined="1" class="embed-field-box">
|
||||||
<label class="is-sr-only" for="embedFieldTitle">Field Title</label>
|
<label class="is-sr-only" for="embedFieldTitle">Field Title</label>
|
||||||
<div style="display: flex;">
|
<div class="is-flex">
|
||||||
<textarea class="discord-field-title field-input message-input autoresize"
|
<textarea class="discord-field-title field-input message-input autoresize"
|
||||||
placeholder="Field Title..." rows="1"
|
placeholder="Field Title..." rows="1"
|
||||||
maxlength="256" id="embedFieldTitle" name="embed_field_title[]"></textarea>
|
maxlength="256" name="embed_field_title[]"></textarea>
|
||||||
<button class="button is-small inline-btn" style="height: 100%; padding: 5px;"><i class="fas fa-arrows-h"></i></button>
|
<button class="button is-small inline-btn">
|
||||||
|
<span class="is-sr-only">Toggle field inline</span><i class="fas fa-arrows-h"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label class="is-sr-only" for="embedFieldValue">Field Value</label>
|
<label class="is-sr-only" for="embedFieldValue">Field Value</label>
|
||||||
<textarea
|
<textarea
|
||||||
class="discord-field-value field-input message-input autoresize "
|
class="discord-field-value field-input message-input autoresize "
|
||||||
placeholder="Field Value..."
|
placeholder="Field Value..."
|
||||||
maxlength="1024" id="embedFieldValue" name="embed_field_value[]"
|
maxlength="1024" name="embed_field_value[]"
|
||||||
rows="1"></textarea>
|
rows="1"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -102,7 +104,7 @@
|
|||||||
<label class="is-sr-only" for="embedFooter">Embed Footer text</label>
|
<label class="is-sr-only" for="embedFooter">Embed Footer text</label>
|
||||||
<textarea class="discord-embed-footer message-input autoresize "
|
<textarea class="discord-embed-footer message-input autoresize "
|
||||||
placeholder="Embed Footer..."
|
placeholder="Embed Footer..."
|
||||||
maxlength="2048" id="embedFooter" name="embed_footer" rows="1"></textarea>
|
maxlength="2048" name="embed_footer" rows="1"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -121,7 +123,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="column is-narrow">
|
<div class="column is-narrow">
|
||||||
<button class="button is-rounded hide-box">
|
<button class="button is-rounded hide-box">
|
||||||
<i class="fas fa-chevron-down"></i>
|
<span class="is-sr-only">Hide reminder</span><i class="fas fa-chevron-down"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -132,20 +134,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="control has-icons-left">
|
<div class="control has-icons-left">
|
||||||
<div class="select">
|
<div class="select">
|
||||||
<select id="channelOption" name="channel" class="channel-selector">
|
<select name="channel" class="channel-selector">
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="icon is-small is-left">
|
<div class="icon is-small is-left">
|
||||||
<i class="fas fa-hashtag"></i>
|
<i class="fas fa-hashtag"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="collapses">
|
<div class="collapses">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Time</label>
|
|
||||||
<div class="control">
|
<div class="control">
|
||||||
|
<label class="label">
|
||||||
|
Time
|
||||||
<input class="input" type="datetime-local" step="1" name="time">
|
<input class="input" type="datetime-local" step="1" name="time">
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -154,13 +157,28 @@
|
|||||||
<div class="control intervalSelector">
|
<div class="control intervalSelector">
|
||||||
<div class="input interval-group">
|
<div class="input interval-group">
|
||||||
<div class="interval-group-left">
|
<div class="interval-group-left">
|
||||||
<input class="w2" type="text" pattern="\d*" name="interval_months" maxlength="2" placeholder=""> <span style="width: 0.5rem"></span> months, <span style="width: 0.5rem"></span>
|
<label>
|
||||||
<input class="w3" type="text" pattern="\d*" name="interval_days" maxlength="4" placeholder=""> <span style="width: 0.5rem"></span> days, <span style="width: 0.5rem"></span>
|
<span class="is-sr-only">Interval months</span>
|
||||||
|
<input class="w2" type="text" pattern="\d*" name="interval_months" maxlength="2" placeholder=""> <span class="half-rem"></span> months, <span class="half-rem"></span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span class="is-sr-only">Interval days</span>
|
||||||
|
<input class="w3" type="text" pattern="\d*" name="interval_days" maxlength="4" placeholder=""> <span class="half-rem"></span> days, <span class="half-rem"></span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span class="is-sr-only">Interval hours</span>
|
||||||
<input class="w2" type="text" pattern="\d*" name="interval_hours" maxlength="2" placeholder="HH">:
|
<input class="w2" type="text" pattern="\d*" name="interval_hours" maxlength="2" placeholder="HH">:
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span class="is-sr-only">Interval minutes</span>
|
||||||
<input class="w2" type="text" pattern="\d*" name="interval_minutes" maxlength="2" placeholder="MM">:
|
<input class="w2" type="text" pattern="\d*" name="interval_minutes" maxlength="2" placeholder="MM">:
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span class="is-sr-only">Interval seconds</span>
|
||||||
<input class="w2" type="text" pattern="\d*" name="interval_seconds" maxlength="2" placeholder="SS">
|
<input class="w2" type="text" pattern="\d*" name="interval_seconds" maxlength="2" placeholder="SS">
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button class="clear"><span class="icon"><i class="fas fa-trash"></i></span></button>
|
<button class="clear"><span class="is-sr-only">Clear interval</span><span class="icon"><i class="fas fa-trash"></i></span></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -193,13 +211,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span style="width: 12px;"></span>
|
<span class="pad-left"></span>
|
||||||
{% if creating %}
|
{% if creating %}
|
||||||
<button class="button is-outlined">
|
<button class="button is-outlined show-modal" data-modal="chooseTemplateModal">
|
||||||
Load Template
|
Load Template
|
||||||
</button>
|
</button>
|
||||||
<button class="button is-success is-outlined" id="createTemplate">
|
<button class="button is-success is-outlined" id="createTemplate">
|
||||||
Create Template
|
<span>Create Template</span> <span class="icon"><i class="fas fa-file-spreadsheet"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<button class="button is-success" id="createReminder">
|
<button class="button is-success" id="createReminder">
|
||||||
<span>Create Reminder</span> <span class="icon"><i class="fas fa-sparkles"></i></span>
|
<span>Create Reminder</span> <span class="icon"><i class="fas fa-sparkles"></i></span>
|
||||||
@ -209,6 +227,7 @@
|
|||||||
<span>Save</span> <span class="icon"><i class="fas fa-save"></i></span>
|
<span>Save</span> <span class="icon"><i class="fas fa-save"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<button class="button is-warning disable-enable">
|
<button class="button is-warning disable-enable">
|
||||||
|
<span class="is-sr-only">Text content filled by CSS</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="button is-danger delete-reminder">
|
<button class="button is-danger delete-reminder">
|
||||||
Delete
|
Delete
|
||||||
|
@ -1,186 +0,0 @@
|
|||||||
<div class="discord-frame">
|
|
||||||
<article class="media">
|
|
||||||
<figure class="media-left">
|
|
||||||
<p class="image is-32x32">
|
|
||||||
<img class="is-rounded" src="/static/img/icon.png" alt="reminder bot icon">
|
|
||||||
</p>
|
|
||||||
</figure>
|
|
||||||
<div class="media-content">
|
|
||||||
<div class="content">
|
|
||||||
<div class="is-hidden-touch">
|
|
||||||
<div class="discord-message-header">
|
|
||||||
Reminder Bot -
|
|
||||||
<label class="is-sr-only" for="reminderDate">Reminder Date</label>
|
|
||||||
<input class="time-input date" placeholder="YYYY/MM/DD"
|
|
||||||
id="reminderDate" name="date">
|
|
||||||
|
|
||||||
<label class="is-sr-only" for="reminderTime">Reminder Time</label>
|
|
||||||
<input class="time-input time" placeholder="HH:MM:SS"
|
|
||||||
id="reminderTime" name="time">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="is-hidden-desktop">
|
|
||||||
<label class="is-sr-only" for="reminderDate">Reminder Date</label>
|
|
||||||
<input class="time-input date" placeholder="YYYY/MM/DD"
|
|
||||||
id="reminderDate" name="date">
|
|
||||||
|
|
||||||
<label class="is-sr-only" for="reminderTime">Reminder Time</label>
|
|
||||||
<input class="time-input time" placeholder="HH:MM:SS"
|
|
||||||
id="reminderTime" name="time">
|
|
||||||
|
|
||||||
<div class="discord-message-header">
|
|
||||||
Reminder Bot
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<label class="is-sr-only" for="messageContent">Message</label>
|
|
||||||
<textarea class="message-input autoresize discord-content preview-mode"
|
|
||||||
placeholder="Message Content..."
|
|
||||||
maxlength="2000" id="messageContent" name="content" rows="1"></textarea>
|
|
||||||
|
|
||||||
<div class="discord-embed">
|
|
||||||
<div class="embed-body">
|
|
||||||
<div class="a">
|
|
||||||
<div class="embed-author-box">
|
|
||||||
<div class="a">
|
|
||||||
<p class="image is-24x24 customizable">
|
|
||||||
<a>
|
|
||||||
<img class="is-rounded preview-mode" src="">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="b">
|
|
||||||
<label class="is-sr-only" for="embedAuthor">Embed Author</label>
|
|
||||||
<textarea
|
|
||||||
class="discord-embed-author message-input preview-mode autoresize"
|
|
||||||
placeholder="Embed Author..." rows="1" maxlength="256"
|
|
||||||
id="embedAuthor" name="embed_author"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label class="is-sr-only" for="embedTitle">Embed Title</label>
|
|
||||||
<textarea class="discord-title message-input preview-mode autoresize"
|
|
||||||
placeholder="Embed Title..."
|
|
||||||
maxlength="256" id="embedTitle" rows="1"
|
|
||||||
name="embed_title"></textarea>
|
|
||||||
<br>
|
|
||||||
<label class="is-sr-only" for="embedDescription">Embed Description</label>
|
|
||||||
<textarea class="discord-description message-input autoresize preview-mode"
|
|
||||||
placeholder="Embed Description..."
|
|
||||||
maxlength="2048" id="embedDescription" name="embed_description"
|
|
||||||
rows="1"></textarea>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="embed-multifield-box">
|
|
||||||
<div class="embed-field-box">
|
|
||||||
<label class="is-sr-only" for="embedFieldTitle">Field Title</label>
|
|
||||||
<textarea
|
|
||||||
class="discord-field-title field-input message-input autoresize preview-mode"
|
|
||||||
placeholder="Field Title..." rows="1"
|
|
||||||
maxlength="256" id="embedFieldTitle"
|
|
||||||
name="embed_field_title[]"></textarea>
|
|
||||||
|
|
||||||
<label class="is-sr-only" for="embedFieldValue">Field Value</label>
|
|
||||||
<textarea
|
|
||||||
class="discord-field-value field-input message-input autoresize preview-mode"
|
|
||||||
placeholder="Field Value..."
|
|
||||||
maxlength="1024" id="embedFieldValue" name="embed_field_value[]"
|
|
||||||
rows="1"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="b">
|
|
||||||
<p class="image thumbnail customizable">
|
|
||||||
<a>
|
|
||||||
<img class="preview-mode" src="">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="image is-400x300 customizable">
|
|
||||||
<a>
|
|
||||||
<img class="preview-mode" src="">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="embed-footer-box">
|
|
||||||
<p class="image is-20x20 customizable">
|
|
||||||
<a>
|
|
||||||
<img class="is-rounded preview-mode" src="">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<label class="is-sr-only" for="embedAuthor">Embed Author</label>
|
|
||||||
<textarea class="discord-embed-footer message-input autoresize preview-mode"
|
|
||||||
placeholder="Embed Footer..."
|
|
||||||
maxlength="2048" id="embedAuthor" name="embed_author" rows="1"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<nav class="level is-mobile">
|
|
||||||
<div class="level-left">
|
|
||||||
<a class="level-item icon-toggle tts-toggle" title="Enable TTS">
|
|
||||||
<p>
|
|
||||||
TTS <span class="icon is-small"><i class="far fa-comment-lines"></i></span>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
<a class="level-item icon-toggle autopin-toggle" title="Enable Autopin">
|
|
||||||
<p>
|
|
||||||
Pin <span class="icon is-small"><i class="far fa-thumbtack"></i></span>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
<span style="width: 12px;"></span>
|
|
||||||
<a class="level-item set-color">
|
|
||||||
<p>
|
|
||||||
Set Embed Color <span class="icon is-small"><i
|
|
||||||
class="far fa-eye-dropper"></i></span>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
<a class="level-item file-upload">
|
|
||||||
<div class="file">
|
|
||||||
<input class="file-input" type="file" name="attachment">
|
|
||||||
<p>
|
|
||||||
Attach File
|
|
||||||
<span class="icon is-small">
|
|
||||||
<i class="far fa-file-upload"></i>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<a class="level-item set-interval">
|
|
||||||
<p>
|
|
||||||
Set Interval <span class="icon is-small"><i class="far fa-repeat"></i></span>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
<span style="width: 12px;"></span>
|
|
||||||
<a class="level-item preview-toggle" title="Preview Message">
|
|
||||||
<p>
|
|
||||||
Preview Mode <span class="icon is-small"><i class="far fa-eye"></i></span>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<nav class="level is-mobile">
|
|
||||||
<div class="level-left">
|
|
||||||
<a class="level-item create-reminder" title="Create Reminder">
|
|
||||||
<p>
|
|
||||||
Create <span class="icon is-small"><i class="far fa-calendar-plus"></i></span>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
<a class="level-item icon-toggle disable-reminder" title="Disable/enable Reminder">
|
|
||||||
<p>
|
|
||||||
Disable <span class="icon is-small"><i class="far fa-comment-slash"></i></span>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
<a class="level-item delete-reminder" title="Delete Reminder">
|
|
||||||
<p>
|
|
||||||
Delete <span class="icon is-small"><i class="far fa-trash"></i></span>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
@ -1,5 +1,4 @@
|
|||||||
<div style="margin: 0 12px 12px 12px;">
|
<div class="create-reminder">
|
||||||
<div class="create-reminder">
|
|
||||||
<strong>Create Reminder</strong>
|
<strong>Create Reminder</strong>
|
||||||
<div id="reminderCreator">
|
<div id="reminderCreator">
|
||||||
{% set creating = true %}
|
{% set creating = true %}
|
||||||
@ -30,7 +29,7 @@
|
|||||||
<div class="column is-narrow">
|
<div class="column is-narrow">
|
||||||
<div class="control has-icons-left">
|
<div class="control has-icons-left">
|
||||||
<div class="select is-small">
|
<div class="select is-small">
|
||||||
<select id="expandAll" style="width: 60px">
|
<select id="expandAll">
|
||||||
<option value="" selected></option>
|
<option value="" selected></option>
|
||||||
<option value="expand">Expand All</option>
|
<option value="expand">Expand All</option>
|
||||||
<option value="collapse">Collapse All</option>
|
<option value="collapse">Collapse All</option>
|
||||||
@ -47,7 +46,6 @@
|
|||||||
<div id="guildReminders">
|
<div id="guildReminders">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/sort.js"></script>
|
<script src="/static/js/sort.js"></script>
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
<div style="margin: 0 12px 12px 12px;">
|
|
||||||
<div class="create-reminder">
|
|
||||||
<p>
|
|
||||||
<strong>Message Designer</strong>
|
|
||||||
</p>
|
|
||||||
{% include "reminder_dashboard/personal_reminder" %}
|
|
||||||
<p style="font-size: 0.8rem;">
|
|
||||||
Most fields are optional. Use 'Preview Mode' to see how the reminder will appear in Discord.
|
|
||||||
Scaling is not exact.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="field">
|
|
||||||
<p class="control">
|
|
||||||
<a class="button is-success">
|
|
||||||
Create
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="personalReminders">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
Loading…
Reference in New Issue
Block a user