first commit
This commit is contained in:
commit
843e6ea7e5
4 changed files with 600 additions and 0 deletions
BIN
background.png
Normal file
BIN
background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1 MiB |
322
input.js
Normal file
322
input.js
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
const expButton = document.getElementById("export");
|
||||
class Variation {
|
||||
constructor(name, text, color, textColor) {
|
||||
this.name = name;
|
||||
this.text = text;
|
||||
this.color = color;
|
||||
this.textColor = textColor;
|
||||
}
|
||||
|
||||
split() {
|
||||
return this.text.split(/\r?\n/);
|
||||
}
|
||||
}
|
||||
|
||||
let variations = [];
|
||||
let userText = [];
|
||||
let name = "new project";
|
||||
|
||||
const box = document.getElementById("inputBox");
|
||||
const project = document.getElementById("project");
|
||||
const newProject = document.getElementById("new");
|
||||
const cpResult = document.getElementById("copy");
|
||||
|
||||
project.addEventListener('click', () => {
|
||||
const result = prompt("Type the new name.", name);
|
||||
if (result) {
|
||||
name = result;
|
||||
reload();
|
||||
}
|
||||
})
|
||||
|
||||
cpResult.addEventListener('click', async () => {
|
||||
const text = userText.join("\n");
|
||||
await navigator.clipboard.writeText(text);
|
||||
alert(text);
|
||||
})
|
||||
|
||||
const newVname = document.querySelector("#newVname");
|
||||
const newVtext = document.querySelector("#newVtext");
|
||||
const newVcolor = document.querySelector("#newVcolor");
|
||||
const newVtcolor = document.querySelector("#newVtcolor");
|
||||
const newVadd = document.querySelector("#newVadd");
|
||||
|
||||
const variationsList = document.querySelector("#variations");
|
||||
|
||||
newVadd.addEventListener('click', e => {
|
||||
if (newVname.value && newVtext.value && newVcolor.value && newVtcolor.value) {
|
||||
variations.push(new Variation(newVname.value, newVtext.value, newVcolor.value, newVtcolor.value));
|
||||
reload();
|
||||
} else {
|
||||
alert("Fill all fields.")
|
||||
}
|
||||
})
|
||||
|
||||
expButton.addEventListener('click', () => {
|
||||
const save = {
|
||||
name: name,
|
||||
vars: variations,
|
||||
usrInput: userText
|
||||
}
|
||||
|
||||
const json = JSON.stringify(save);
|
||||
const blob = new Blob([json], {type: 'application/json'});
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = `lyGEN-${name}.json`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
})
|
||||
|
||||
|
||||
const blankline = document.createElement("p");
|
||||
blankline.textContent = "Blank line";
|
||||
blankline.className = "stringParagraph blankline";
|
||||
|
||||
function closeAllPopups() {
|
||||
const popups = document.querySelectorAll("aside");
|
||||
popups.forEach(popup => {
|
||||
popup.classList.add("closed");
|
||||
});
|
||||
}
|
||||
|
||||
function togglePopup(tag) {
|
||||
const doc = document.querySelector(tag);
|
||||
if (doc.classList.contains('closed')) {
|
||||
closeAllPopups()
|
||||
}
|
||||
doc.classList.toggle("closed");
|
||||
}
|
||||
|
||||
function reload() {
|
||||
listVariations();
|
||||
showVariations();
|
||||
autosave();
|
||||
project.textContent = name;
|
||||
}
|
||||
|
||||
function populatePreview() {
|
||||
const doc = document.querySelector("#previewTextBox");
|
||||
doc.innerHTML = "";
|
||||
userText.forEach(line => {
|
||||
e = document.createElement('p');
|
||||
e.textContent = line;
|
||||
e.id = "previewText";
|
||||
doc.appendChild(e);
|
||||
});
|
||||
}
|
||||
|
||||
newProject.addEventListener('click', () => {
|
||||
if(confirm("The current project will be deleted, continue?")) {
|
||||
variations = [];
|
||||
name = "new project";
|
||||
userText = [];
|
||||
reload();
|
||||
}
|
||||
})
|
||||
|
||||
function createFileInput() {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = '.json,application/json';
|
||||
input.style.display = 'none';
|
||||
|
||||
input.addEventListener('change', handleFileUpload);
|
||||
|
||||
document.body.appendChild(input);
|
||||
|
||||
input.click();
|
||||
|
||||
input.addEventListener('blur', () => {
|
||||
document.body.removeChild(input);
|
||||
});
|
||||
}
|
||||
|
||||
const importButton = document.getElementById('import');
|
||||
importButton.addEventListener('click', createFileInput);
|
||||
|
||||
function autosave() {
|
||||
console.log("Autosaving...");
|
||||
|
||||
const save = {
|
||||
name: name,
|
||||
vars: variations,
|
||||
usrInput: userText
|
||||
}
|
||||
|
||||
const json = JSON.stringify(save);
|
||||
|
||||
localStorage.setItem("autosave", json);
|
||||
}
|
||||
|
||||
function loadAutoSave() {
|
||||
const saveData = localStorage.getItem("autosave");
|
||||
if (saveData) {
|
||||
try {
|
||||
const save = JSON.parse(saveData);
|
||||
|
||||
variations = save.vars.map(v =>
|
||||
new Variation(v.name, v.text, v.color, v.textColor)
|
||||
);
|
||||
|
||||
name = save.name || "new project";
|
||||
userText = save.usrInput || [];
|
||||
|
||||
reload();
|
||||
} catch (error) {
|
||||
console.error("Error loading autosave:", error);
|
||||
localStorage.removeItem("autosave");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleFileUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
if (file) {
|
||||
if (file.type !== 'application/json' && !file.name.endsWith('.json')) {
|
||||
alert('Please select a JSON file');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
try {
|
||||
const saveData = JSON.parse(e.target.result);
|
||||
|
||||
if (!saveData.vars || !Array.isArray(saveData.vars)) {
|
||||
throw new Error('Invalid file structure');
|
||||
}
|
||||
|
||||
variations = saveData.vars.map(v =>
|
||||
new Variation(
|
||||
v.name || 'Unnamed Variation',
|
||||
v.text || '',
|
||||
v.color || '#FFFFFF',
|
||||
v.textColor || '#000000'
|
||||
)
|
||||
);
|
||||
|
||||
name = saveData.name || "new project";
|
||||
userText = saveData.usrInput || [];
|
||||
|
||||
reload();
|
||||
|
||||
alert('File successfully loaded');
|
||||
} catch (error) {
|
||||
console.error("Error parsing file:", error);
|
||||
alert('Invalid file format. Please select a valid LyGEN project file.');
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = function() {
|
||||
alert('Error reading file');
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}
|
||||
|
||||
function listVariations() {
|
||||
variationsList.innerHTML = "";
|
||||
|
||||
variations.forEach(variation => {
|
||||
const div = document.createElement("div");
|
||||
div.style.color = variation.textColor;
|
||||
div.style.backgroundColor = variation.color;
|
||||
div.className = "variation";
|
||||
|
||||
const pName = document.createElement("p");
|
||||
pName.textContent = variation.name;
|
||||
pName.className = "variationName";
|
||||
|
||||
const copy = document.createElement("p");
|
||||
copy.textContent = "cp";
|
||||
copy.className = "variationCopy";
|
||||
|
||||
const remove = document.createElement("p");
|
||||
remove.textContent = "d";
|
||||
remove.className = "variationDelete";
|
||||
|
||||
const up = document.createElement("p");
|
||||
up.textContent = "↑";
|
||||
up.className = "variationUp";
|
||||
|
||||
div.appendChild(pName);
|
||||
div.appendChild(copy);
|
||||
div.appendChild(remove);
|
||||
div.appendChild(up);
|
||||
|
||||
variationsList.appendChild(div);
|
||||
|
||||
remove.addEventListener('click', () => {
|
||||
variations = variations.filter(v => v !== variation);
|
||||
reload();
|
||||
})
|
||||
|
||||
copy.addEventListener('click', async () => {
|
||||
await navigator.clipboard.writeText(variation.text);
|
||||
alert(variation.text);
|
||||
})
|
||||
|
||||
function moveItem(array, index, shift) {
|
||||
if (index > 0) {
|
||||
const item = array.splice(index, 1)[0];
|
||||
array.splice(index + shift, 0, item);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
up.addEventListener('click', () => {
|
||||
variations = moveItem(variations, variations.indexOf(variation), -1);
|
||||
reload();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function showVariations() {
|
||||
box.innerHTML = '';
|
||||
const maxLenght = Math.max(...variations.map(variation => variation.split().length));
|
||||
|
||||
for (let i = 0; i < maxLenght; i++) {
|
||||
const pContainer = document.createElement("div");
|
||||
pContainer.className = `paragraphContainer paragraphContainer${i}`;
|
||||
var styleElem = document.head.appendChild(document.createElement("style"));
|
||||
styleElem.innerHTML = `.paragraphContainer${i}:before {content: "${i + 1}";}`;
|
||||
|
||||
variations.forEach(variation => {
|
||||
if (variation.split()[i]) {
|
||||
const p = document.createElement("p");
|
||||
p.className = `string-${variation.name}-paragraph stringParagraph`;
|
||||
p.textContent = variation.split()[i];
|
||||
p.style.backgroundColor = variation.color;
|
||||
p.style.color = variation.textColor;
|
||||
pContainer.appendChild(p);
|
||||
} else {
|
||||
pContainer.appendChild(blankline);
|
||||
}
|
||||
});
|
||||
|
||||
const ibox = document.createElement("input");
|
||||
ibox.type = "text";
|
||||
ibox.className = `ibox ibox${i}`
|
||||
ibox.value = userText[i] ?? "";
|
||||
ibox.dataset.lineNumber = i;
|
||||
ibox.placeholder = "...";
|
||||
ibox.addEventListener('change', () => {
|
||||
userText[ibox.dataset.lineNumber] = ibox.value;
|
||||
autosave();
|
||||
});
|
||||
ibox.addEventListener('change', () => {
|
||||
populatePreview();
|
||||
});
|
||||
pContainer.appendChild(ibox);
|
||||
box.appendChild(pContainer);
|
||||
}
|
||||
}
|
||||
|
||||
loadAutoSave();
|
||||
populatePreview();
|
||||
reload();
|
||||
52
main.html
Normal file
52
main.html
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="input.js" defer></script>
|
||||
<title>lyGEN</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<header>
|
||||
<h1 class="movingGradient">lyGEN</h1>
|
||||
<div id="headerOptions">
|
||||
<p class="movingGradient">
|
||||
<a id="new">New</a> -
|
||||
<a id="export">Export</a> -
|
||||
<a id="import">Import</a> -
|
||||
<a id="copy">Copy result</a> -
|
||||
<a id="optinsbtn" onclick="togglePopup('#options')">Options</a> -
|
||||
<a id="optinsbtn" onclick="togglePopup('#preview')">Preview</a>
|
||||
</p>
|
||||
<p id="project"></p>
|
||||
</div>
|
||||
</header>
|
||||
<div id="inputBox"></div>
|
||||
</main>
|
||||
<aside class="closed" id="options">
|
||||
<h2>Options</h2>
|
||||
<div id="settingsOptions">
|
||||
<div id="newVariation">
|
||||
<h3>New variation</h3>
|
||||
<p>Name</p>
|
||||
<input type="text" id="newVname">
|
||||
<p>Content</p>
|
||||
<textarea style="resize: vertical; height: 20em;" type="text" name="" id="newVtext"></textarea>
|
||||
<p>Color</p>
|
||||
<input type="color" name="" id="newVcolor">
|
||||
<p>Text color</p>
|
||||
<input type="color" name="" id="newVtcolor">
|
||||
<button id="newVadd">Add</button>
|
||||
</div>
|
||||
|
||||
<div id="variations"></div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<aside class="closed" id="Preview">
|
||||
<h2>Preview</h2>
|
||||
<div id="previewTextBox"></div>
|
||||
</aside>
|
||||
</body>
|
||||
</html>
|
||||
226
style.css
Normal file
226
style.css
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
/* scrollbar-width: thich; */
|
||||
scrollbar-color: white black;
|
||||
--border-contrast: darkgray;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#previewText {
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
margin-bottom: .6em;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
#previewText::after {
|
||||
content: "↩";
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: black;
|
||||
color: white;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.stringParagraph {
|
||||
width: fit-content;
|
||||
padding: .2em;
|
||||
border-left: medium solid white;
|
||||
transition: .2s;
|
||||
}
|
||||
|
||||
/* .stringParagraph:hover {
|
||||
border-left-width: 1.05em;
|
||||
}
|
||||
|
||||
.stringParagraph:hover::before {
|
||||
content: ">";
|
||||
color: black;
|
||||
margin-left: -1em;
|
||||
} */
|
||||
|
||||
.paragraphContainer::before {
|
||||
color: white;
|
||||
/* text-decoration:underline; */
|
||||
border: medium solid white;
|
||||
border-bottom: none;
|
||||
padding: .2em;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
#inputBox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
padding: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.ibox {
|
||||
transition: .2s;
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-left: medium solid white;
|
||||
font-size: 1em;
|
||||
color: lightgray;
|
||||
}
|
||||
|
||||
.ibox:focus {
|
||||
border-left-width: 1em;
|
||||
outline: none;
|
||||
min-width: calc(3ch + 1em);
|
||||
}
|
||||
|
||||
input, textarea, button {
|
||||
transition: .2s;
|
||||
background-color: black;
|
||||
border: medium solid var(--border-contrast);
|
||||
color: white;
|
||||
padding: .2em;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
input:focus, textarea:focus, button:hover, button:focus {
|
||||
outline: none;
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
main {
|
||||
flex-grow: 1;
|
||||
overflow-x:hidden;
|
||||
}
|
||||
|
||||
aside h2 {
|
||||
font-size: xx-large;
|
||||
}
|
||||
|
||||
aside {
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
right: 0;
|
||||
transition: 1s;
|
||||
width: 25vw;
|
||||
padding: 1em;
|
||||
background-color: white;
|
||||
color: black;
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
aside::before {
|
||||
filter: grayscale(1);
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
opacity: .2;
|
||||
|
||||
background-size: contain;
|
||||
background-position: left bottom;
|
||||
background-image: url('/background.png');
|
||||
background-repeat: no-repeat;
|
||||
|
||||
z-index: 0;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
aside > * {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
aside.closed {
|
||||
transform: translateX(100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: .4em;
|
||||
border-bottom: medium solid white;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
margin-bottom: 0px;
|
||||
margin-right: .6em;
|
||||
}
|
||||
|
||||
#headerOptions a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#settingsOptions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
#newVariation {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .4em;
|
||||
}
|
||||
|
||||
.blankline {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#variations {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.variation {
|
||||
display: flex;
|
||||
border: medium solid white;
|
||||
padding: .4em;
|
||||
}
|
||||
|
||||
.variationName {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.variationDelete {
|
||||
color: red;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#project {
|
||||
color: lightgray;
|
||||
}
|
||||
|
||||
.movingGradient {
|
||||
background: linear-gradient(to right, white, darkgray, white);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
animation: movingGradientAnimation 6s ease-in-out infinite;
|
||||
background-size: 400% 100%;
|
||||
}
|
||||
|
||||
@keyframes movingGradientAnimation {
|
||||
0%,100% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue