From 56c315c301902c8bacf3658ae1abf4e501c64ff0 Mon Sep 17 00:00:00 2001 From: ktyl Date: Sun, 4 Aug 2024 19:15:29 +0100 Subject: [PATCH] feat: startup splash for user configuration --- index.html | 7 ++ main.js | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++--- styles.css | 96 ++++++++++++++++++++++--- 3 files changed, 291 insertions(+), 19 deletions(-) diff --git a/index.html b/index.html index 787d831..273db76 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,13 @@ +
+ + + + Choose some interests! +
+
diff --git a/main.js b/main.js index 4b9aa7c..a64d7d1 100644 --- a/main.js +++ b/main.js @@ -8,7 +8,34 @@ const adjectives = [ "analytical", "motivated", "solution-focused", "committed", "agile" ]; +const interests = [ + "music", "comedy", "travel", "technology", "hiking", "nature", "food", "movies", + "culture", "art", "activism", "community", "books", "baking", "creativity", "fitness", + "fashion", "wellness", "history", "adventure", "gaming", "gardening", "sustainability", + "coding", "coffee", "DIY", "crafts", "pets", "animals", "humor", "languages", "sports", + "competition", "meditation", "mindfulness", "design", "concerts", "innovation", "museums", + "future", "writing", "relaxation", "photography", "compassion", "nutrition", "style", + "restaurants", "gadgets", "inspiration", "literature", "outdoors", "wildlife", "conservation", + "motivation", "beauty", "culinary arts", "festivals", "exploration", "knowledge", "camping", + "archeology", "triathlon", "endurance", "luxury", "wine", "fine dining", "audio equipment", + "sound quality", "startups", "entrepreneurship", "extreme sports", "philosophy", "survival", + "environment", "politics", "running", "gastronomy", "genres", "software", "current events", + "recipes", "listening", "discovery", "expression", "reading", "recommendations", "news", + "analysis", "trends", "dining", "reviews", "rescue", "welfare", "health", "artists", "cooking" +]; + +var localUser = { + user: null, + interests: [], + postingStyle: null +}; +var splashStep = 0; +const maxInterests = 3; + +// configuration const localMode = false; +const showSplash = false; + const blockContainer = document.getElementById("block-container"); const postCountElem = document.getElementById("post-count"); const postTotalElem = document.getElementById("post-total"); @@ -215,13 +242,18 @@ function makePostFromJson(json) { } function getCurrentUser() { + // return some default values if we didn't do the initial configuration + if (!showSplash) { + return { + "user": "ktyl", + "interests": ["trains", "trains", "trains"], + "posting_style": "borderline maniacal train content" + }; + } + return { - "user": "theChief", - "interests": [ - "gen-ai", - "blockchain", - "nfts" - ], + "user": localUser.user, + "interests": localUser.interests, "posting_style": "just the most truly inane takes" }; } @@ -243,12 +275,10 @@ function writePost(postCallback) { body: "local mode post (local mode post)" }); postCallback(post); - //blockContainer.insertBefore(post.getElement(), getTopPost()); } else { fetch("https://api.wayfarer.games/singularity/generate-posts.php", request) .then(response => response.json()) .then(makePostFromJson) - //.then(post => blockContainer.insertBefore(post.getElement(), getTopPost())); .then(postCallback); } } @@ -302,6 +332,162 @@ function init() { window.addEventListener("scroll", handleInfiniteScroll); } + +function chooseInterest(interest) { + if (localUser.interests.length == maxInterests) { + console.error(`can't choose more than ${maxInterests} interests`); + return; + } + + localUser.interests.push(interest); + + const interestsTextElem = document.getElementById("interests-text"); + + if (localUser.interests.length != maxInterests) { + interestsTextElem.innerHTML = getInterestsTextValue(localUser.interests.length); + return; + } + + const advanceButtonElem = document.getElementById("advance-button"); + advanceButtonElem.innerHTML = "Begin!"; + advanceButtonElem.style.visibility = "visible"; + + interestsTextElem.remove(); + const interestsListElem = document.getElementById("interest-selection"); + interestsListElem.remove(); +} + +function getInterestsSubset() { + const count = 20; + let subset = []; + + while (subset.length < count) { + const interest = interests[Math.floor(Math.random() * interests.length)]; + + // skip if it's already included + if (subset.includes(interest)) + continue; + + // skip if the user has already chosen it + if (localUser.interests.includes(interest)) + continue; + + subset.push(interest); + } + + return subset; +} + +function populateSplashInterests() { + + const rootElem = document.getElementById("interest-selection"); + if (rootElem == null) + return; + + // clear existing interests + rootElem.innerHTML = ""; + + const interestsSubset = getInterestsSubset(); + + for (let i = 0; i < interestsSubset.length; i++) { + const interest = interestsSubset[i]; + const listItemElem = document.createElement("li"); + rootElem.appendChild(listItemElem); + + const buttonElem = document.createElement("a"); + buttonElem.innerHTML = `#${interest}`; + buttonElem.addEventListener("click", () => { + chooseInterest(interest); + populateSplashInterests(); + }); + listItemElem.appendChild(buttonElem); + } +} + +function getInterestsTextValue(numChosenInterests) { + return `Choose some interests! (${numChosenInterests}/${maxInterests})`; +} + +function usernameInputUpdated(event) { + const inputElem = document.getElementById("username"); + const buttonElem = document.getElementById("advance-button"); + const isNameEmpty = inputElem.value.length == ""; + buttonElem.style.visibility = isNameEmpty ? "hidden" : "visible"; + + if (isNameEmpty) + return; + + if (event.key == "Enter") { + advanceSplash(); + } +} + +function chooseName() { + // check that a name has been chosen + const inputElem = document.getElementById("username"); + if (!inputElem.value) { + console.error("a name needs to be entered!"); + return; + } + + splashStep = 1; + localUser.user = inputElem.value; + + // TODO: disable button until name has been chosen + + // TODO: insert interest selection elements before name input + //writePost(post => blockContainer.insertBefore(post.getElement(), getTopPost())); + const splashElem = document.getElementById("start-splash"); + + const interestsTextElem = document.createElement("p"); + interestsTextElem.innerHTML = getInterestsTextValue(0); + interestsTextElem.id = "interests-text"; + interestsTextElem.className = "center"; + splashElem.insertBefore(interestsTextElem, inputElem); + + const interestsListElem = document.createElement("ul"); + interestsListElem.className = "center"; + interestsListElem.id = "interest-selection"; + splashElem.insertBefore(interestsListElem, inputElem); + + populateSplashInterests(); + + // remove name input + inputElem.remove(); + + const advanceButtonElem = document.getElementById("advance-button"); + advanceButtonElem.style.visibility = "hidden"; + + splashStep = 1; +} + +function chooseInterests() { + if (localUser.interests.length < maxInterests) { + console.error(`need to choose ${maxInterests} interests`); + return; + } + + console.log("TODO: generate user posting style"); +} + +function removeSplash() { + document.getElementById("start-splash").remove(); +} + +function advanceSplash() { + switch(splashStep) { + case 0: + chooseName(); + break; + case 1: + chooseInterests(); + removeSplash(); + break; + default: + console.error(`nothing defined for splash step ${splashStep}`); + } +} + function loadDataFromEndpoint(endpoint, callback) { fetch(endpoint) .then(response => response.json()) @@ -311,6 +497,7 @@ function loadDataFromEndpoint(endpoint, callback) { }); } + const usersUrl = localMode ? "users.json" : "https://api.wayfarer.games/singularity/users.json"; const postsUrl = localMode ? "posts.json" : "https://api.wayfarer.games/singularity/posts.json"; loadDataFromEndpoint(usersUrl, json => { users = json.users; }); @@ -333,3 +520,7 @@ loadDataFromEndpoint(postsUrl, json => { postTotalElem.innerHTML = Object.keys(posts).length; }); + +if (!showSplash) { + removeSplash(); +} diff --git a/styles.css b/styles.css index 51f224b..64865d3 100644 --- a/styles.css +++ b/styles.css @@ -1,15 +1,17 @@ :root { --header-height: 64px; - --background-color: #374955; - --accent-color: #86b1cc; + --blue-gray: #374955; + --sky-blue: #86b1cc; --comment-column-width: 3px; } body { + margin: 0; + padding: 0; font-family: "Poppins", sans-serif; font-weight: 400; font-style: normal; - background-color: var(--background-color); + background-color: var(--sky-blue); } @media only screen and (min-width: 800px) { @@ -23,6 +25,77 @@ body { } } +#start-splash { + position: fixed; + width: 100%; + height: 100%; + padding: 0; + margin: 0; + background-color: white; + z-index: 1; +} + +.center { + display: block; + margin: auto; + padding: auto; + text-align: center; +} + +#start-splash img { + max-width: 40vw; + margin-top: 10vh; +} + +#start-splash input { + margin: 2em auto; + border: none; + background-color: var(--sky-blue); + color: white; + border-radius: 16px; + font-size: 1.5em; + padding: 4px 8px; +} + +#advance-button { + width: 20%; + margin: 2em auto; + color: white; + background-color: var(--sky-blue); + text-align: center; + visibility: hidden; + padding: 4px 8px; + border-radius: 16px; +} + +#interests-text { + color: var(--blue-gray); +} + +#interest-selection { + width: 80%; + padding: 8px; + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +#interest-selection li { + display: inline; + margin: .5em; +} + +#interest-selection li a { + padding: 4px 8px; + border-radius: 16px; + color: white; + background-color: var(--sky-blue); + transition: all 200ms ease-in-out; +} + +#interest-selection li a:hover { + background-color: var(--blue-gray); +} #block-container { display: flex; @@ -51,19 +124,20 @@ body { border-radius: calc(var(--header-height) / 2); margin-top: calc(var(--header-height) / 8); padding: calc(var(--header-height) / 8) calc(var(--header-height) / 4); - background-color: var(--accent-color); - color: var(--backround-color); + background-color: var(--sky-blue); + color: white; cursor: pointer; transition: all 200ms ease-in-out; } .reply-button:hover { - background-color: var(--background-color); + background-color: var(--blue-gray); color: white; } .reply-button:active { background-color: white; + color: var(--blue-gray); } .post-header { @@ -82,16 +156,16 @@ body { .write-post { cursor: pointer; - color: var(--background-color); + color: var(--blue-gray); } .write-post:hover { - background-color: var(--accent-color); + background-color: var(--sky-blue); color: white; } .write-post:active { - background-color: var(---background-color); + background-color: var(---blue-gray); } .write-post h2 { @@ -102,7 +176,7 @@ body { a { text-decoration: none; - color: var(--background-color); + color: var(--blue-gray); } .pfp { @@ -118,7 +192,7 @@ a { .post:not(.block) { margin-top: calc(var(--header-height) / 4); - border-left: var(--comment-column-width) solid var(--accent-color); + border-left: var(--comment-column-width) solid var(--sky-blue); padding-left: calc(var(--header-height) / 2 - var(--comment-column-width)); }