diff --git a/README.md b/README.md
index 7288683..045fe68 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,4 @@ or https://infopg.web.app
it's like pronouns.page but i made it
### todo
-* social links (currently wip)
* pride flags
-* add key at bottom of /u/... pages
diff --git a/_server.py b/_server.py
index b8d8dba..26fdb56 100644
--- a/_server.py
+++ b/_server.py
@@ -9,6 +9,7 @@ import shutil
import flask
import json
import os
+import re
from DotIndex import DotIndex
from typing import Union, Callable
@@ -18,6 +19,81 @@ from werkzeug.middleware.proxy_fix import ProxyFix
app = flask.Flask(__name__)
app.url_map.strict_slashes = False
+SOCIALS_REGEX = {
+ "discord" : re.compile(r"^(?!.*\.\.)(?=.{2,32}$)[a-z0-9_.]+$"),
+ "twitter" : re.compile(r"^(?!.*twitter)(?!.*admin)[a-z0-9_]{1,15}$", re.IGNORECASE),
+ "github" : re.compile(r"^(?!.*--)[a-z0-9](?:[a-z0-9-]{0,37}[a-z0-9])?$", re.IGNORECASE),
+ "twitch" : re.compile(r"^[a-z0-9_]{4,25}$", re.IGNORECASE),
+ "reddit" : re.compile(r"^[a-z0-9_-]{3,20}$", re.IGNORECASE),
+ "snapchat" : re.compile(r"^(?=.{3,15}$)[a-z0-9]+(?:[_.-][a-z0-9]+)?$", re.IGNORECASE),
+ "instagram" : re.compile(r"^[a-z0-9_.]{1,30}$", re.IGNORECASE),
+ "facebook" : re.compile(r"^([a-z0-9].*){1,50}$", re.IGNORECASE),
+ "tiktok" : re.compile(r"^[a-z0-9_.]{1,25}$", re.IGNORECASE),
+ "smiggins" : re.compile(r"^[a-z0-9_-]{1,18}$"),
+ "tringl" : re.compile(r"^[a-z0-9_]{1,24}$")
+}
+
+SOCIAL_ICONS = {
+ "discord": '',
+ "facebook": '',
+ "github": '',
+ "instagram": '',
+ "reddit": '',
+ "smiggins": '',
+ "snapchat": '',
+ "tiktok": '',
+ "tringl": '',
+ "twitch": '',
+ "twitter": ''
+}
+
+SOCIAL_INFO = {
+ "discord": {
+ "link": None,
+ "prefix": ""
+ },
+ "facebook": {
+ "link": "https://www.facebook.com/%q",
+ "prefix": ""
+ },
+ "github": {
+ "link": "https://github.com/%q",
+ "prefix": ""
+ },
+ "instagram": {
+ "link": "https://www.instagram.com/%q/",
+ "prefix": ""
+ },
+ "reddit": {
+ "link": "https://www.reddit.com/u/%q",
+ "prefix": "/u/"
+ },
+ "smiggins": {
+ "link": "https://trinkey.pythonanywhere.com/u/%q",
+ "prefix": "@"
+ },
+ "snapchat": {
+ "link": "https://www.snapchat.com/add/%q",
+ "prefix": ""
+ },
+ "tiktok": {
+ "link": "https://www.tiktok.com/@%q",
+ "prefix": ""
+ },
+ "tringl": {
+ "link": "https://ngl.pythonanywhere.com/m/%q",
+ "prefix": "@"
+ },
+ "twitch": {
+ "link": "https://www.twitch.tv/%q",
+ "prefix": ""
+ },
+ "twitter": {
+ "link": "https://twitter.com/%q",
+ "prefix": "@"
+ }
+}
+
def validate_color(color: str) -> bool:
if len(color) != 7 or color[0] != "#":
return False
@@ -28,12 +104,14 @@ def validate_color(color: str) -> bool:
return True
-def sort_list(l: list[list[str]]) -> list[list[str]]:
+def sort_list(l: list[list[str]], alphabetical=True) -> list[list[str]]:
output = []
for i in l:
- if i[0] and i[1] in ["1", "2", "3", "4"]:
+ if i[0] and (not alphabetical and (i[1] in ["1", "2", "3", "4"]) or (alphabetical and i[1])):
output.append(i)
+ if alphabetical:
+ return sorted(output, key=lambda x: x[1] + x[0])
return sorted(output, key=lambda x: {"1": "d", "2": "c", "3": "b", "4": "a"}[x[1]] + x[0])
def return_dynamic_content_type(content: Union[str, bytes], content_type: str="text/html") -> flask.Response:
@@ -73,7 +151,7 @@ def generate_token(username: str, passhash: str) -> str:
return sha(sha(f"{username}:{passhash}") + "among us in real life, sus, sus")
def list_public(
- sort: str="alphabetical",
+ sort: str="random",
page: int=0,
limit: int=25
) -> dict:
@@ -148,6 +226,21 @@ def get_template(json, username):
inner = add_to_output(inner, json, "compliments", "Compliments");
inner = add_to_output(inner, json, "relationship", "Relationship
Descriptions");
+ try:
+ social = json.social # type: ignore
+ inner += '
Social Links
'
+
+ for i in social:
+ if SOCIAL_INFO[i[1]]["link"]:
+ inner += f"
"
+ else:
+ inner += f"
{SOCIAL_ICONS[i[1]]} {SOCIAL_INFO[i[1]]['prefix']}{escape_html(i[0])}
"
+
+ inner += "
"
+
+ except AttributeError as e:
+ print(e)
+
inner += ""
return title, inner, styles, embed
@@ -155,6 +248,7 @@ def get_template(json, username):
def get_user_page(user):
user = user.lower()
x = open(f"{CONTENT_DIRECTORY}user.html", "r").read()
+
try:
user_json = json.loads(open(f"{SAVING_DIRECTORY}{user}.json", "r").read())
except FileNotFoundError:
@@ -162,7 +256,11 @@ def get_user_page(user):
title, inner, styles, embed = get_template(user_json, user)
- return x.replace(" 0 and len(i[0]) < 48:
+ if len(i) == 2 and int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
names.append(i)
user_data["names"] = sort_list(names)
if "pronouns" in x:
pronouns = []
for i in x["pronouns"]:
- if int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
+ if len(i) == 2 and int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
pronouns.append(i)
user_data["pronouns"] = sort_list(pronouns)
if "honorifics" in x:
honorifics = []
for i in x["honorifics"]:
- if int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
+ if len(i) == 2 and int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
honorifics.append(i)
user_data["honorifics"] = sort_list(honorifics)
if "compliments" in x:
compliments = []
for i in x["compliments"]:
- if int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
+ if len(i) == 2 and int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
compliments.append(i)
user_data["compliments"] = sort_list(compliments)
if "relationship" in x:
relationship = []
for i in x["relationship"]:
- if int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
+ if len(i) == 2 and int(i[1]) in [1, 2, 3, 4] and len(i[0]) > 0 and len(i[0]) < 48:
relationship.append(i)
user_data["relationship"] = sort_list(relationship)
+ if "social" in x:
+ social = []
+ for i in x["social"]:
+ if len(i) == 2 and i[1] in SOCIALS_REGEX and SOCIALS_REGEX[i[1]].match(i[0]):
+ social.append(i)
+ user_data["social"] = sort_list(social)
+
f = open(f"{SAVING_DIRECTORY}{username}.json", "w")
f.write(json.dumps(user_data))
f.close()
diff --git a/public/css/base.css b/public/css/base.css
index 3eb8cc5..f04c9cd 100644
--- a/public/css/base.css
+++ b/public/css/base.css
@@ -1,23 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,700;1,400;1,700&display=swap');
-@font-face {
- font-family: 'FontAwesome Solid';
- src: url('https://site-assets.fontawesome.com/releases/v6.5.1/webfonts/fa-solid-900.woff2');
-}
-
-@font-face {
- font-family: 'FontAwesome Solid';
- src: url('https://site-assets.fontawesome.com/releases/v6.5.1/webfonts/fa-solid-900.woff2');
-}
-
-.fa-s {
- font-family: 'FontAwesome Solid', sans-serif;
-}
-
-.fa-r {
- font-family: 'FontAwesome Regular', sans-serif;
-}
-
:root {
--text: #aaaaaa;
--background: #333333;
@@ -42,21 +24,21 @@ body::-webkit-scrollbar { display: none; }
body {
background-color: var(--background);
color: var(--text);
- font-family: 'Poppins', "FontAwesome Regular", 'Arial';
+ font-family: 'Poppins', 'Arial';
padding: 5vh 0;
text-align: center;
- font-size: 14px;
+ font-size: 16px;
margin: 0px;
overflow-x: hidden;
word-wrap: break-word;
}
@media screen and (min-width: 1025px) {
- body { font-size: 16px; }
+ body { font-size: 18px; }
}
@media screen and (max-width: 565px) {
- body { font-size: 16px; padding: 5vh 3vw; }
+ body { font-size: 18px; padding: 5vh 3vw; }
}
button {
@@ -95,6 +77,13 @@ option {
font-size: 1.1em;
}
+footer {
+ opacity: 50%;
+ position: fixed;
+ bottom: 10px;
+ right: 10px;
+}
+
textarea { background-color: var(--secondary-low-opacity); }
textarea:disabled { opacity: 70%; pointer-events: none; }
diff --git a/public/css/editor.css b/public/css/editor.css
index fc690f6..396a170 100644
--- a/public/css/editor.css
+++ b/public/css/editor.css
@@ -1,5 +1,21 @@
input:not([type]), input[type="text"] {
width: 10em;
+ border: 2px solid #0000;
+}
+
+#social input.bad,
+#social input.bad:focus {
+ border-color: var(--accent);
+ outline-color: var(--accent);
+}
+
+.added.wider input:not([type]),
+.added.wider input[type="text"] {
+ width: 14em;
+}
+
+.wider {
+ max-width: 22em;
}
#input-display-name {
diff --git a/public/css/page.css b/public/css/page.css
index c4cee04..ebd3c9b 100644
--- a/public/css/page.css
+++ b/public/css/page.css
@@ -1,3 +1,7 @@
+body {
+ padding-bottom: calc(20px + 8em);
+}
+
svg {
width: 0.9em;
height: 0.9em;
@@ -5,13 +9,14 @@ svg {
fill: var(--text);
}
-#word-container {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: center;
- row-gap: 5em;
- column-gap: 2em;
+a, a:visited, a:link {
+ color: var(--text);
+ text-decoration-color: var(--text);
+}
+
+footer a, footer a:visited, footer a:link {
+ color: var(--accent);
+ text-decoration-color: var(--accent);
}
.added {
@@ -24,3 +29,38 @@ svg {
.added h2 {
text-align: center;
}
+
+.added div {
+ margin-bottom: 0.2em;
+}
+
+#word-container {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: center;
+ row-gap: 5em;
+ column-gap: 2em;
+}
+
+#key {
+ position: fixed;
+ text-align: left;
+ bottom: 10px;
+ opacity: 50%;
+}
+
+@media screen and (min-width: 566px) {
+ #key {
+ left: 10px;
+ }
+}
+
+@media screen and (max-width: 565px) {
+ #key {
+ position: fixed;
+ text-align: left;
+ bottom: calc(10px + 2em);
+ right: 10px;
+ }
+}
diff --git a/public/editor.html b/public/editor.html
index a660dea..25ebc21 100644
--- a/public/editor.html
+++ b/public/editor.html
@@ -15,4 +15,4 @@
-
\ No newline at end of file
+
Social Links
' + + for i in social: + if SOCIAL_INFO[i[1]]["link"]: + inner += f"