shtuff
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
BASE_URL=localhost:3004
|
||||
BASE_URL=localhost:3003
|
||||
JWT_SECRET=950b15c8c1c8a27dd716bba3ab51d96ce49afa85cae72884cf22e936e1bc0cb9
|
||||
ENV=development
|
||||
@@ -12,7 +12,7 @@ var ENV string
|
||||
|
||||
// URLs
|
||||
var BASE_URL string
|
||||
const PORT = "3004"
|
||||
const PORT = "3003"
|
||||
|
||||
// Auth
|
||||
var JWT_SECRET string
|
||||
|
||||
@@ -32,14 +32,6 @@ body {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--green);
|
||||
transition: background .2s, padding .2s, color .2s;
|
||||
padding: 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: var(--green);
|
||||
color: var(--tan);
|
||||
|
||||
Binary file not shown.
@@ -1,19 +0,0 @@
|
||||
css(`
|
||||
nav-bar {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
`)
|
||||
|
||||
export default class NavBar extends HTMLElement {
|
||||
|
||||
connectedCallback() {
|
||||
|
||||
this.innerHTML += /* html */ `
|
||||
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("nav-bar", NavBar)
|
||||
@@ -1,581 +0,0 @@
|
||||
css(`
|
||||
questionnaire- {
|
||||
display: grid;
|
||||
grid-template-columns: 250px 1fr;
|
||||
gap: 20px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
margin-top: 17vh;
|
||||
}
|
||||
|
||||
.toc {
|
||||
position: sticky;
|
||||
top: 17vh;
|
||||
align-self: start;
|
||||
background: var(--tan);
|
||||
padding: 10px;
|
||||
border: 1px solid var(--brown);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.toc h2 {
|
||||
margin-top: 0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.toc a {
|
||||
display: block;
|
||||
margin: 5px 0;
|
||||
text-decoration: none;
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.toc a.active {
|
||||
font-weight: bold;
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
section {
|
||||
border: 1px solid var(--brown);
|
||||
margin-bottom: 2vh;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
background: none;
|
||||
user-select: none;
|
||||
transition: background 0.2s, border 0.2s, color 0.2s;
|
||||
}
|
||||
|
||||
.section-content {
|
||||
scroll-margin-top: 20px;
|
||||
padding-bottom: 40px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
outline: 1px solid #ddbb36;
|
||||
border: 1px solid #c4a52f
|
||||
}
|
||||
|
||||
/* Normal state */
|
||||
form button {
|
||||
transition: all 0.3s ease;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Loading: morph into circle + pulse */
|
||||
form button.loading {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
animation: pulse 1s infinite;
|
||||
}
|
||||
|
||||
/* Success state */
|
||||
button.success {
|
||||
background: #28a745;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
width: auto;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); opacity: 1; }
|
||||
50% { transform: scale(1.1); opacity: 0.7; }
|
||||
100% { transform: scale(1); opacity: 1; }
|
||||
}
|
||||
`)
|
||||
|
||||
export default class Questionnaire extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.pages = [
|
||||
{ title: "Demographic Information", slug: "demographic", content: this.demographicContent() },
|
||||
{ title: "Contact Information", slug: "contact", content: this.contactContent() },
|
||||
{ title: "Personal History", slug: "personal-history", content: this.personalHistoryContent() },
|
||||
{ title: "Ancestry", slug: "ancestry", content: this.ancestryContent() },
|
||||
{ title: "Skills", slug: "skills", content: this.skillsContent() },
|
||||
{ title: "Interest", slug: "interest", content: this.interestContent() },
|
||||
{ title: "Criminal Record", slug: "criminal", content: this.criminalContent() },
|
||||
{ title: "Political Perspectives", slug: "political", content: this.politicalContent() },
|
||||
{ title: "Religious/Philosophical Views", slug: "religious", content: this.religiousContent() },
|
||||
{ title: "Federal Employment", slug: "federal-employment", content: this.federalEmploymentContent() },
|
||||
{ title: "Social Perspectives", slug: "social", content: this.socialContent() },
|
||||
];
|
||||
this.pageHTML = {};
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
async fetchData() {
|
||||
try {
|
||||
const res = await fetch("/api/get-application");
|
||||
if (!res.ok) throw new Error(`HTTP error ${res.status}`);
|
||||
this.data = await res.json();
|
||||
console.log(this.data)
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch questionnaire:", err);
|
||||
this.data = {};
|
||||
}
|
||||
this.render()
|
||||
}
|
||||
|
||||
render() {
|
||||
this.Layout();
|
||||
this.Forms();
|
||||
this.setupScrollSpy();
|
||||
this.populateFormData();
|
||||
this.markSectionsComplete();
|
||||
}
|
||||
|
||||
Layout() {
|
||||
this.innerHTML = /* html */`
|
||||
<nav class="toc">
|
||||
<h2>Contents</h2>
|
||||
${this.pages.map(p => `
|
||||
<a href="#${p.slug}" data-slug="${p.slug}">${p.title}</a>
|
||||
`).join("")}
|
||||
<a href="#submit">Submit</a>
|
||||
</nav>
|
||||
<div class="sections">
|
||||
${this.pages.map(p => /* html */`
|
||||
<section id="${p.slug}" class="section-content">
|
||||
<h1 style="margin-left: 3rem; margin-top: 3rem">${p.title}</h1>
|
||||
<div class="form-container">
|
||||
<form></form>
|
||||
</div>
|
||||
</section>
|
||||
`).join("")}
|
||||
<section id="submit" class="section-content">
|
||||
<h1 style="margin-left: 3rem; margin-top: 3rem">Submit Application</h1>
|
||||
<button style="margin-left: 3rem; margin-top: 3rem; background-color: gray" disabled>Submit</button>
|
||||
</section>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
Forms() {
|
||||
this.pages.forEach(page => {
|
||||
const form = this.querySelector(`#${page.slug} form`);
|
||||
if (form) form.innerHTML = page.content;
|
||||
form.innerHTML += `<button type="submit">Save</button>`
|
||||
form.addEventListener("submit", this.onFormSubmit)
|
||||
});
|
||||
}
|
||||
|
||||
populateFormData() {
|
||||
Object.entries(this.data).forEach(([key, value]) => {
|
||||
const fields = document.querySelectorAll(`[name="${key}"]`);
|
||||
if (!fields.length) return;
|
||||
|
||||
fields.forEach(field => {
|
||||
if (field.type === "checkbox" || field.type === "radio") {
|
||||
if (Array.isArray(value)) {
|
||||
field.checked = value.includes(field.value);
|
||||
} else {
|
||||
field.checked = field.value === value;
|
||||
}
|
||||
} else if (field.tagName === "SELECT" && field.multiple && Array.isArray(value)) {
|
||||
Array.from(field.options).forEach(opt => {
|
||||
opt.selected = value.includes(opt.value);
|
||||
});
|
||||
} else {
|
||||
field.value = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
markSectionsComplete() {
|
||||
let allFormsComplete = true
|
||||
let forms = document.querySelectorAll("form")
|
||||
for(let i =0; i<forms.length; i++) {
|
||||
let form = forms[i]
|
||||
if(form.checkValidity()) {
|
||||
form.closest("section").style.backgroundColor = "#0080003d"
|
||||
let toc = document.querySelector(`[data-slug=${form.closest("section").id}]`)
|
||||
if(!toc.innerHTML.includes("✓"))
|
||||
toc.innerHTML += " ✓"
|
||||
} else {
|
||||
allFormsComplete = false
|
||||
}
|
||||
}
|
||||
|
||||
if(allFormsComplete) {
|
||||
let button = document.querySelector("section#submit button")
|
||||
button.style.backgroundColor = ""
|
||||
button.removeAttribute("disabled")
|
||||
button.addEventListener("click", () => window.location.href = "/complete")
|
||||
}
|
||||
}
|
||||
|
||||
setupScrollSpy() {
|
||||
const tocLinks = this.querySelectorAll(".toc a");
|
||||
const sections = this.querySelectorAll(".section-content");
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
const id = entry.target.id;
|
||||
history.replaceState(null, "", `#${id}`);
|
||||
tocLinks.forEach(link => {
|
||||
link.classList.toggle("active", link.dataset.slug === id);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, {
|
||||
rootMargin: "-50% 0px -50% 0px", // middle of screen
|
||||
threshold: 0
|
||||
});
|
||||
|
||||
sections.forEach(section => observer.observe(section));
|
||||
}
|
||||
|
||||
onFormSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
let form = e.target
|
||||
let button = form.querySelector('button[type="submit"]');
|
||||
|
||||
if (!form.checkValidity()) {
|
||||
// Let the browser display native validation errors
|
||||
return;
|
||||
}
|
||||
|
||||
const showButtonLoading = () => {
|
||||
button.classList.add('loading');
|
||||
button.disabled = true;
|
||||
button.textContent = '';
|
||||
}
|
||||
|
||||
const showButtonError = () => {
|
||||
button.classList.remove('loading');
|
||||
button.disabled = false;
|
||||
button.textContent = 'Save';
|
||||
if(!form.querySelector("p .error")) {
|
||||
form.parentElement.appendChild(html(`<p class="error" style="color: red">There has been an error. Please try again.</p>`))
|
||||
}
|
||||
}
|
||||
|
||||
const showButtonSuccess = () => {
|
||||
if(form.parentElement.querySelector("p")) {
|
||||
form.parentElement.querySelector("p").remove()
|
||||
}
|
||||
button.classList.remove('loading');
|
||||
button.classList.add('success');
|
||||
button.textContent = 'Success!';
|
||||
console.log(this)
|
||||
this.markSectionsComplete()
|
||||
}
|
||||
|
||||
showButtonLoading()
|
||||
|
||||
// Collect form data
|
||||
const data = new FormData(form);
|
||||
const values = {};
|
||||
data.forEach((v, k) => {
|
||||
if (values[k]) {
|
||||
// Already an array? push new value
|
||||
if (Array.isArray(values[k])) {
|
||||
values[k].push(v);
|
||||
} else {
|
||||
values[k] = [values[k], v];
|
||||
}
|
||||
} else {
|
||||
values[k] = v;
|
||||
}
|
||||
});
|
||||
|
||||
fetch('/api/application-save', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(values)
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
throw new Error(`Server error: ${res.status}`);
|
||||
}
|
||||
return res.text();
|
||||
})
|
||||
.then(responseData => {
|
||||
console.log(form, form.parentElement)
|
||||
showButtonSuccess()
|
||||
console.log('Server response:', responseData);
|
||||
})
|
||||
.catch(err => {
|
||||
showButtonError()
|
||||
console.error('Submission error:', err);
|
||||
});
|
||||
|
||||
console.log("Form submitted:", values);
|
||||
}
|
||||
|
||||
demographicContent() {
|
||||
return /* html */`
|
||||
<label for="firstName">First Name *</label>
|
||||
<input type="text" name="firstName" class="form-control" required>
|
||||
<br><br>
|
||||
|
||||
<label for="lastName">Last Name *</label>
|
||||
<input type="text" name="lastName" class="form-control" required>
|
||||
<br><br>
|
||||
|
||||
<label for="age">Age *</label>
|
||||
<input type="text" name="age" class="form-control" required>
|
||||
<br><br>
|
||||
|
||||
<label for="gender">Gender *</label>
|
||||
<select name="gender" class="form-control" required>
|
||||
<option value="">Select...</option>
|
||||
<option value="male">Male</option>
|
||||
<option value="female">Female</option>
|
||||
</select>
|
||||
<br><br>
|
||||
|
||||
<label for="ethnicity">Type of Application *</label>
|
||||
<select name="applicationType" class="form-control" required>
|
||||
<option value="">Select...</option>
|
||||
<option value="single">Single</option>
|
||||
<option value="couple">Couple</option>
|
||||
<option value="family">Family</option>
|
||||
</select>
|
||||
<br><br>
|
||||
|
||||
<label for="sexualOrientation">Sexual Orientation *</label>
|
||||
<select name="sexualOrientation" class="form-control" required>
|
||||
<option value="">Select...</option>
|
||||
<option value="straight">Straight</option>
|
||||
<option value="gay">Gay</option>
|
||||
<option value="bisexual">Bisexual</option>
|
||||
<option value="other">Other</option>
|
||||
</select>
|
||||
<br><br>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
contactContent() {
|
||||
return /* html */`
|
||||
<div class="form-group">
|
||||
<label for="telegram">Telegram Username *</label>
|
||||
<input type="text" name="telegram" class="form-control" required>
|
||||
<small style="display:block;margin-top:.25rem;color:#666;">A Telegram account is required to be interviewed by the PMA</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email-2">Secondary Email</label>
|
||||
<input type="email" name="email-2" class="form-control">
|
||||
<small style="display:block;margin-top:.25rem;color:#666;">Not required - you may add a secondary email in case our messages don't reach you</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="phone">Phone Number</label>
|
||||
<input type="tel" name="phone" class="form-control">
|
||||
<small style="display:block;margin-top:.25rem;color:#666;">Not required, but recommended if you don't provide a Telegram handle.</small>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
personalHistoryContent() {
|
||||
return /* html */`
|
||||
<div class="form-group">
|
||||
<label for="personalHistory">Where did you come from, where did you grow up, and where do you live now? *</label>
|
||||
<textarea name="personalHistory" class="form-control" required minlength="10"></textarea>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
ancestryContent() {
|
||||
return /* html */`
|
||||
<div class="form-group">
|
||||
<p>Please select all that apply to your ancestry/heritage:</p>
|
||||
<div class="ancestry-grid">
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="english"> English</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="irish"> Irish</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="scottish"> Scottish</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="welsh"> Welsh</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="german"> German</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="french"> French</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="dutch"> Dutch</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="scandinavian"> Scandinavian</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="slavic"> Slavic</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="balkan"> Balkan</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="iberian"> Iberian</label>
|
||||
<label class="ancestry-option"><input type="checkbox" name="ancestry" value="other">Other</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="ancestryDetails">Tell us more about your ancestry and family history *</label>
|
||||
<textarea name="ancestryDetails" class="form-control" required minlength="20" placeholder="Please provide details about your family background, heritage, and any ancestral connections you're aware of."></textarea>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
skillsContent() {
|
||||
return /* html */`
|
||||
<div class="form-group">
|
||||
<label for="skills">Describe any special skills or trades you have. *</label>
|
||||
<textarea name="skills" class="form-control" required minlength="50" placeholder="e.g., carpentry, plumbing, electrical, masonry, welding"></textarea>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
interestContent() {
|
||||
return /* html */`
|
||||
<div class="form-group">
|
||||
<label for="interest">Why are you interested in Return To The Land, and how did you find out about us? *</label>
|
||||
<textarea name="interest" class="form-control" required minlength="20"></textarea>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
criminalContent() {
|
||||
return /* html */`
|
||||
<label for="criminal">Do you have a criminal record? If so, please explain. Otherwise, just say "no". *</label>
|
||||
<textarea name="criminal" class="form-control" required></textarea>
|
||||
<br><br>
|
||||
`;
|
||||
}
|
||||
|
||||
politicalContent() {
|
||||
return /* html */`
|
||||
<label for="politicsNotes">Give a quick summary of your political ideas. *</label>
|
||||
<textarea name="politicsNotes" class="form-control" style="width:100%;min-height:120px" required minlength="40"></textarea>
|
||||
<br><br>
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
religiousContent() {
|
||||
return /* html */`
|
||||
<div class="form-group">
|
||||
<label>Do you identify with a particular religion? *</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="religionIdent" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="religionIdent" value="no"> No</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="religionName">If yes, which?</label>
|
||||
<input name="religionName" class="form-control" placeholder="e.g., Catholic, Orthodox, Protestant, Deist, Other">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Do you regularly attend services or observances?</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="attendance" value="weekly"> Weekly</label>
|
||||
<label><input type="radio" name="attendance" value="monthly"> Monthly</label>
|
||||
<label><input type="radio" name="attendance" value="occasionally"> Occasionally</label>
|
||||
<label><input type="radio" name="attendance" value="never"> Never</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="philosophy">Briefly describe your moral or philosophical outlook *</label>
|
||||
<textarea name="philosophy" class="form-control" required></textarea>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
federalEmploymentContent() {
|
||||
return /* html */`
|
||||
<div class="form-group">
|
||||
<label>Are you currently employed by, or otherwise receive funds to perform work for, the United States federal government or a contractor/affiliate/partner? *</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="employedByGovernment" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="employedByGovernment" value="no"> No</label>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
socialContent() {
|
||||
return /* html */`
|
||||
<p class="note">Please answer these questions regarding controversial topics. Anything that needs further explanation can be done in the interview.</p>
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<label>I support gay marriage *</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="gays" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="gays" value="no"> No</label>
|
||||
<label><input type="radio" name="gays" value="neutral"> Neutral</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>I support transgenderism *</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="trannies" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="trannies" value="no"> No</label>
|
||||
<label><input type="radio" name="trannies" value="neutral"> Neutral</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>I support foreign immigration *</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="immigration" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="immigration" value="no"> No</label>
|
||||
<label><input type="radio" name="immigration" value="neutral"> Neutral</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>I support the COVID vaccine and mask *</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="vax" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="vax" value="no"> No</label>
|
||||
<label><input type="radio" name="vax" value="neutral"> Neutral</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>I support abortion *</label>
|
||||
<div class="form-group">
|
||||
<label><input type="radio" name="abortion" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="abortion" value="no"> No</label>
|
||||
<label><input type="radio" name="abortion" value="neutral"> Neutral</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>I support segregation *</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="segregation" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="segregation" value="no"> No</label>
|
||||
<label><input type="radio" name="segregation" value="neutral"> Neutral</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>I support procreation *</label>
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="procreation" value="yes" required> Yes</label>
|
||||
<label><input type="radio" name="procreation" value="no"> No</label>
|
||||
<label><input type="radio" name="procreation" value="neutral"> Neutral</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Multiculturalism preference *</label>
|
||||
<div class="radio-row">
|
||||
<label style="display:block;margin:.35rem 0"><input type="radio" name="multiculturalism" value="yes" required> I prefer a community with a variety of different ancestral origins</label>
|
||||
<label style="display:block;margin:.35rem 0"><input type="radio" name="multiculturalism" value="no"> I prefer a community where everyone shares common continental ancestry</label>
|
||||
<label style="display:block;margin:.35rem 0"><input type="radio" name="multiculturalism" value="neutral"> Neutral</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>How often do you think about the Roman empire? *</label>
|
||||
<div class="radio-row">
|
||||
<label style="display:block;margin:.35rem 0"><input type="radio" name="romanEmpire" value="daily" required> Every day, at least once</label>
|
||||
<label style="display:block;margin:.35rem 0"><input type="radio" name="romanEmpire" value="weekly"> A few times a week, probably</label>
|
||||
<label style="display:block;margin:.35rem 0"><input type="radio" name="romanEmpire" value="rarely"> Very rarely</label>
|
||||
<label style="display:block;margin:.35rem 0"><input type="radio" name="romanEmpire" value="never"> Never</label>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("questionnaire-", Questionnaire);
|
||||
@@ -1,97 +0,0 @@
|
||||
:root {
|
||||
--bar-bg: #ccc;
|
||||
--bar-fill: var(--green, #4caf50);
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
position: absolute;
|
||||
top: 20vh;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: var(--green);
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: calc(20vh + 30px);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
max-width: 90vw;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.section:hover {
|
||||
background: var(--red);
|
||||
color: var(--tan);
|
||||
}
|
||||
|
||||
.section:hover .status {
|
||||
color: var(--tan);
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* Questionnaire Pages */
|
||||
.form-container {
|
||||
max-width: 800px;
|
||||
margin: 2rem auto;
|
||||
padding: 2rem;
|
||||
/* background: rgba(255, 255, 255, 0.9); */
|
||||
}
|
||||
|
||||
.form-container input {
|
||||
background: var(--tan);
|
||||
border: 1px solid var(--brown);
|
||||
}
|
||||
|
||||
.form-container select {
|
||||
background: var(--tan);
|
||||
border: 1px solid var(--brown);
|
||||
}
|
||||
|
||||
.form-group { margin-bottom: 1.5rem; }
|
||||
label { display: block; margin-bottom: 0.5rem; font-weight: bold; }
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
background: var(--tan);
|
||||
border: 1px solid var(--brown)
|
||||
}
|
||||
|
||||
textarea.form-control { min-height: 120px; resize: vertical; }
|
||||
|
||||
.btn {
|
||||
background-color: var(--green);
|
||||
color: #fff;
|
||||
padding: 0.5rem 1rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn:hover { background-color: var(--dark-green); }
|
||||
|
||||
.btn-outline { background: none; border: 1px solid var(--green); color: var(--green); }
|
||||
|
||||
.radio-row { margin: 0.25rem 0; }
|
||||
.note { color: #444; margin: 0.5rem 0 0 0; }
|
||||
|
||||
/* Grid/option helpers used by ancestry */
|
||||
.ancestry-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
|
||||
.ancestry-option { border: 1px solid var(--brown); padding: 1rem; border-radius: 4px; cursor: pointer; transition: all 0.2s; }
|
||||
.ancestry-option:hover { border-color: var(--green); background-color: rgba(76, 175, 80, 0.1); }
|
||||
.ancestry-option input[type="checkbox"] { margin-right: 0.5rem; }
|
||||
@@ -1,23 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Hyperia | Application</title>
|
||||
<link rel="stylesheet" href="_/code/shared.css">
|
||||
<link rel="icon" href="_/icons/logo.svg">
|
||||
<script src="_/code/util.js"></script>
|
||||
<link rel="stylesheet" href="index.css">
|
||||
<script type="module">
|
||||
import NavBar from "./components/NavBar.js"
|
||||
import Questionnaire from "./components/Questionnaire.js"
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<nav-bar></nav-bar>
|
||||
|
||||
<questionnaire-></questionnaire->
|
||||
|
||||
<div style="position: fixed; bottom: 2vh; left: 1vw">
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#items {
|
||||
position: absolute;
|
||||
top: 45vh;
|
||||
top: 47vh;
|
||||
left: 50vw;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
text-underline-offset: 5px;
|
||||
transition: background .02s, color .2s;
|
||||
user-select: none;
|
||||
color: black;
|
||||
|
||||
display: inline-block; /* makes background and padding behave */
|
||||
padding: 0.2em 0.5em; /* adds breathing room */
|
||||
@@ -51,6 +52,12 @@
|
||||
background: var(--red); /* background color works now */
|
||||
color: white; /* optional: change text color for contrast */
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
#title {
|
||||
font-size: 30vw
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script src="_/code/util.js"></script>
|
||||
<script type="module">
|
||||
@@ -66,11 +73,12 @@
|
||||
<img src="_/icons/left_plant.svg" style="position: absolute; left: 25%; top: 23vh; width: 70%; transform: translateX(-50%)">
|
||||
<img src="_/icons/right_plant.svg" style="position: absolute; left: 75%; top: 23vh; width: 70%; transform: translateX(-50%)">
|
||||
<div style="height: 2vh"></div>
|
||||
<span style="font-family: Canterbury; color: black; font-size: 5vh;">A <br>Society</span>
|
||||
<span style="font-family: Canterbury; color: black; font-size: 4.5vh;">A <br>Classical <br> Christian <br> Society</span>
|
||||
<div style="height: 2vh"></div>
|
||||
<div style="color: black; font-size: 2.2vh; z-index: 1; cursor: default;">
|
||||
<a>ABOUT</a> | <a>SERVICES</a> | <a>JOIN</a>
|
||||
<div style="color: black; font-size: 2vh; z-index: 1; cursor: default;">
|
||||
<a href="signin">SIGN IN</a>
|
||||
<a href="join">JOIN</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
77
ui/public/pages/join.html
Normal file
77
ui/public/pages/join.html
Normal file
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Hyperia</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="_/icons/logo.svg">
|
||||
<link rel="stylesheet" href="_/code/shared.css">
|
||||
<link rel="stylesheet" href="index.css">
|
||||
<style>
|
||||
:root {
|
||||
--green: #0B5538;
|
||||
--tan: #FFDFB4;
|
||||
--red: #BC1C02;
|
||||
--brown: #c6a476
|
||||
}
|
||||
|
||||
#items {
|
||||
position: absolute;
|
||||
top: 45vh;
|
||||
left: 50vw;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; /* centers children horizontally */
|
||||
text-align: center; /* ensures text inside spans is centered */
|
||||
}
|
||||
|
||||
#title {
|
||||
font-size: 10vh;
|
||||
position: absolute;
|
||||
left: 2vw;
|
||||
top: 2vh;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: default;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 5px;
|
||||
transition: background .02s, color .2s;
|
||||
user-select: none;
|
||||
padding: 4px;
|
||||
border-radius: 5px;
|
||||
display: inline-block; /* makes background and padding behave */
|
||||
padding: 0.2em 0.5em; /* adds breathing room */
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
background: var(--green);
|
||||
color: var(--tan);
|
||||
}
|
||||
|
||||
a:active {
|
||||
background: var(--red); /* background color works now */
|
||||
color: white; /* optional: change text color for contrast */
|
||||
}
|
||||
</style>
|
||||
<script src="_/code/util.js"></script>
|
||||
<script type="module">
|
||||
import PageFooter from "./components/Footer.js"
|
||||
import NavBar from "./components/NavBar.js"
|
||||
import SideBar from "./components/SideBar.js"
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<span id="title" style="font-family: Canterbury; color: var(--red); margin-bottom: 10vh">hyperia</span>
|
||||
<div id="items">
|
||||
|
||||
</div>
|
||||
<script>
|
||||
Array.from($("a*")).forEach((link) => {
|
||||
link.addEventListener("click", () => window.history.pushState("", "", link.innerHTML.toLowerCase()))
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
122
ui/public/pages/signin.html
Normal file
122
ui/public/pages/signin.html
Normal file
@@ -0,0 +1,122 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Hyperia</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="_/icons/logo.svg">
|
||||
<link rel="stylesheet" href="_/code/shared.css">
|
||||
<link rel="stylesheet" href="index.css">
|
||||
<style>
|
||||
:root {
|
||||
--green: #0B5538;
|
||||
--tan: #FFDFB4;
|
||||
--red: #BC1C02;
|
||||
--brown: #c6a476
|
||||
}
|
||||
|
||||
#items {
|
||||
position: absolute;
|
||||
top: 45vh;
|
||||
left: 50vw;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; /* centers children horizontally */
|
||||
text-align: center; /* ensures text inside spans is centered */
|
||||
}
|
||||
|
||||
#title {
|
||||
font-size: 10vh;
|
||||
position: absolute;
|
||||
left: 2vw;
|
||||
top: 2vh;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: default;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 5px;
|
||||
transition: background .02s, color .2s;
|
||||
user-select: none;
|
||||
padding: 4px;
|
||||
border-radius: 5px;
|
||||
display: inline-block; /* makes background and padding behave */
|
||||
padding: 0.2em 0.5em; /* adds breathing room */
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
background: var(--green);
|
||||
color: var(--tan);
|
||||
}
|
||||
|
||||
a:active {
|
||||
background: var(--red); /* background color works now */
|
||||
color: white; /* optional: change text color for contrast */
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
border-top: 2px solid var(--green);
|
||||
border-bottom: 2px solid var(--green);
|
||||
height: 2em;
|
||||
width: 15vw;
|
||||
padding: 0.2em;
|
||||
transition: border .2s, padding .2s;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
padding: 0.4em;
|
||||
border-top: 2px solid var(--red);
|
||||
border-bottom: 2px solid var(--red);
|
||||
}
|
||||
|
||||
input:focus::placeholder {
|
||||
color: var(--red)
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:focus {
|
||||
transition: background-color 600000s 0s, color 600000s 0s;
|
||||
}
|
||||
input[data-autocompleted] {
|
||||
background-color: #c7a67b !important;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
input {
|
||||
width: 50vw
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script src="_/code/util.js"></script>
|
||||
<script type="module">
|
||||
import PageFooter from "./components/Footer.js"
|
||||
import NavBar from "./components/NavBar.js"
|
||||
import SideBar from "./components/SideBar.js"
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<span onclick="window.location = '/'"id="title" style="cursor: default; font-family: Canterbury; color: var(--red); margin-bottom: 10vh">hyperia</span>
|
||||
<div id="items">
|
||||
<input placeholder="email"></input>
|
||||
<br>
|
||||
<input placeholder="password"></input>
|
||||
</div>
|
||||
<script>
|
||||
Array.from($("a*")).forEach((link) => {
|
||||
link.addEventListener("click", () => window.history.pushState("", "", link.innerHTML.toLowerCase()))
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user