add form for creating new tops

This commit is contained in:
neri 2022-10-11 12:30:29 +02:00
parent a97f9f4980
commit 3f0e2e4321
4 changed files with 214 additions and 1 deletions

View File

@ -1,7 +1,9 @@
# WikiJs Metabot # WikiJs Metabot
Ein Skript was die Page-Listings auf [https://wiki.ctdo.de](https://wiki.ctdo.de) Ein Skript was die Page-Listings auf [https://wiki.ctdo.de](https://wiki.ctdo.de)
automatisch befüllt automatisch befüllt.
Das Repo enthält außerdem die Konfiguration für ein kleines Topictreff-Form mit dem man neue Tops
anlegen kann.
## Verwendung ## Verwendung

56
topic-form.css Normal file
View File

@ -0,0 +1,56 @@
.new-top {
display: flex;
flex-direction: column;
margin: 1rem 0;
width: max-content;
max-width: 100%;
}
.top-title {
display: flex;
margin-bottom: 1rem;
width: 60ch;
max-width: 100%;
border-radius: .5rem;
}
.top-title:focus-within {
outline: 1px solid #1976d2;
}
.theme--dark .top-title:focus-within {
outline: 1px solid #ffffff;
}
.top-title-input {
flex-grow: 1;
max-width: unset;
outline: none;
padding: .5rem;
color: #424242;
background-color: #eceff1;
border-radius: 0 .5rem .5rem 0;
}
.theme--dark .top-title-input {
color: #bdbdbd;
background-color: #3b3b3b;
}
.top-title-input-prefix {
padding: 1rem .5rem 1rem 1rem;
background-color: #607d8b;
flex-shrink: 0;
color: #ffffffb2;
border-radius: .5rem 0 0 .5rem;
}
.top-button {
align-self: end
}
.top-progress-spinner {
width: 22px;
height: 22px;
margin-left: .5rem;
}

29
topic-form.html Normal file
View File

@ -0,0 +1,29 @@
<!-- prettier-ignore -->
<form class="new-top theme--copy">
<div class="top-title">
<div class="top-title-input-prefix">
TOP <span class="next-top-number">000</span> -
</div>
<input id="top-input" class="top-title-input theme--copy" placeholder="Titel"/>
</div>
<blockquote id="top-error" class="is-danger" style="display: none;">
<p>
Fehler beim erstellen des Tops:<br>
<span id="top-error-content"></span>
</p>
</blockquote>
<button id="top-button" class="top-button theme--copy v-btn v-btn--depressed v-btn--disabled v-size--large primary" type="button">
<div class="v-btn__content">
Neues TOP anlegen
<div id="top-spinner" style="display: none;" class="top-progress-spinner v-progress-circular v-progress-circular--indeterminate">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="22 22 44 44" style="transform: rotate(0deg);">
<circle fill="transparent" cx="44" cy="44" r="20" stroke-width="4" stroke-dasharray="125.664" stroke-dashoffset="125.66370614359172px" class="v-progress-circular__overlay">
</circle>
</svg>
<div class="v-progress-circular__info"></div>
</div>
</div>
</button>
</form>

126
topic-form.js.html Normal file
View File

@ -0,0 +1,126 @@
<script>
function copyTheme() {
const appClasses = [...document.getElementById('app').classList];
const appTheme = appClasses.find((c) => c.startsWith('theme--'));
for (const element of document.getElementsByClassName('theme--copy')) {
element.classList.replace('theme--copy', appTheme);
}
}
function setupForm() {
const button = document.getElementById('top-button');
const input = document.getElementById('top-input');
const spinner = document.getElementById('top-spinner');
const errorBox = document.getElementById('top-error');
const errorContent = document.getElementById('top-error-content');
input.oninput = () => {
if (input.value === '') {
button.classList.add('v-btn--disabled');
button.disabled = true;
} else {
button.classList.remove('v-btn--disabled');
button.disabled = false;
}
};
button.onclick = async () => {
button.classList.add('v-btn--disabled');
button.disabled = true;
input.disabled = true;
spinner.style = '';
errorBox.style = 'display: none;';
try {
await createNewTop(input.value);
} catch (error) {
errorBox.style = '';
errorContent.textContent = error.message;
}
button.classList.remove('v-btn--disabled');
button.disabled = false;
input.disabled = false;
spinner.style = 'display: none;';
};
}
async function getNextTopNumber() {
const result = await graphql(
'query { pages { list(tags: ["top"]) { path } } }'
);
const topNumbers = result.data.pages.list
.map((page) => page.path)
.map((path) => path.split('/'))
.map((pathSegments) => pathSegments[pathSegments.length - 1])
.map((lastSegment) => Number(lastSegment))
.filter((topNumber) => !!topNumber);
return Math.max(...topNumbers) + 1;
}
async function insertNextTopNumbers() {
const nextTopNumber = await getNextTopNumber();
for (const element of document.getElementsByClassName('next-top-number')) {
element.textContent = nextTopNumber;
}
}
async function createNewTop(title) {
const nextTopNumber = await getNextTopNumber();
const templateResult = await graphql(`
query {
pages {
single(id: 477) {
content
description
editor
isPublished
isPrivate
locale
tags {
tag
}
title
}
}
}
`);
if (templateResult.errors && templateResult.errors.length !== 0) {
throw new Error(templateResult.errors[0].message);
}
const template = templateResult.data.pages.single;
template.tags = template.tags.map((tag) => tag.tag);
template.path = `verein/topictreff/top/${nextTopNumber}`;
template.title = `TOP ${nextTopNumber} - ${title}`;
const pageData = Object.entries(template)
.map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
.map((data) => {
console.log(data);
return data;
})
.join(', ');
const result = await graphql(`
mutation {
pages {
create(${pageData}) {
responseResult {
succeeded
errorCode
message
}
}
}
}
`);
const response = result.data.pages.create.responseResult;
if (response.succeeded) {
window.location = '/e/' + template.path;
} else {
throw new Error(response.message);
console.log({ response });
}
}
isElementLoaded('.contents').then(() => {
copyTheme();
setupForm();
insertNextTopNumbers();
});
</script>