Add about and website to profile. Improve layout.
This commit is contained in:
parent
f3ac806c4b
commit
24bf7067d5
@ -39,6 +39,8 @@ function confirm_setup(): void {
|
|||||||
username TEXT NOT NULL,
|
username TEXT NOT NULL,
|
||||||
display_name TEXT NOT NULL,
|
display_name TEXT NOT NULL,
|
||||||
password_hash TEXT NOT NULL,
|
password_hash TEXT NOT NULL,
|
||||||
|
about TEXT NULL,
|
||||||
|
website TEXT NULL,
|
||||||
mood TEXT NULL
|
mood TEXT NULL
|
||||||
)");
|
)");
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ function get_emojis_with_labels(): array {
|
|||||||
return [
|
return [
|
||||||
'faces' => [
|
'faces' => [
|
||||||
['😀', 'grinning face'],
|
['😀', 'grinning face'],
|
||||||
['😃', 'grinning face with big eyes'],
|
|
||||||
['😄', 'grinning face with smiling eyes'],
|
['😄', 'grinning face with smiling eyes'],
|
||||||
['😁', 'beaming face with smiling eyes'],
|
['😁', 'beaming face with smiling eyes'],
|
||||||
['😆', 'grinning squinting face'],
|
['😆', 'grinning squinting face'],
|
||||||
@ -26,41 +25,31 @@ function get_emojis_with_labels(): array {
|
|||||||
['😜', 'winking face with tongue'],
|
['😜', 'winking face with tongue'],
|
||||||
['😝', 'squinting face with tongue'],
|
['😝', 'squinting face with tongue'],
|
||||||
['🤪', 'zany face'],
|
['🤪', 'zany face'],
|
||||||
['🤨', 'face with raised eyebrow'],
|
['🦸', 'superhero'],
|
||||||
|
['🦹', 'supervillain'],
|
||||||
|
['🧙', 'mage'],
|
||||||
|
['🧛', 'vampire'],
|
||||||
|
['🧟', 'zombie'],
|
||||||
|
['🧞', 'genie'],
|
||||||
],
|
],
|
||||||
'gestures' => [
|
'gestures' => [
|
||||||
['👋', 'waving hand'],
|
['👋', 'waving hand'],
|
||||||
['🤚', 'raised back of hand'],
|
|
||||||
['🖐️', 'hand with fingers splayed'],
|
|
||||||
['✋', 'raised hand'],
|
|
||||||
['🖖', 'vulcan salute'],
|
['🖖', 'vulcan salute'],
|
||||||
['👌', 'OK hand'],
|
['👌', 'OK hand'],
|
||||||
['🤌', 'pinched fingers'],
|
['🤌', 'pinched fingers'],
|
||||||
['🤏', 'pinching hand'],
|
|
||||||
['✌️', 'victory hand'],
|
['✌️', 'victory hand'],
|
||||||
['🤞', 'crossed fingers'],
|
['🤞', 'crossed fingers'],
|
||||||
['🤟', 'love-you gesture'],
|
['🤟', 'love-you gesture'],
|
||||||
['🤘', 'sign of the horns'],
|
['🤘', 'sign of the horns'],
|
||||||
['🤙', 'call me hand'],
|
['🤙', 'call me hand'],
|
||||||
['👈', 'backhand index pointing left'],
|
|
||||||
['👉', 'backhand index pointing right'],
|
|
||||||
['👆', 'backhand index pointing up'],
|
|
||||||
['🖕', 'middle finger'],
|
|
||||||
['👇', 'backhand index pointing down'],
|
|
||||||
['☝️', 'index pointing up'],
|
|
||||||
['👍', 'thumbs up'],
|
['👍', 'thumbs up'],
|
||||||
['👎', 'thumbs down'],
|
['👎', 'thumbs down'],
|
||||||
['✊', 'raised fist'],
|
['✊', 'raised fist'],
|
||||||
['👊', 'oncoming fist'],
|
['👊', 'oncoming fist'],
|
||||||
['🤛', 'left-facing fist'],
|
|
||||||
['🤜', 'right-facing fist'],
|
|
||||||
],
|
],
|
||||||
'nature' => [
|
'nature' => [
|
||||||
['☀️', 'sun'],
|
['☀️', 'sun'],
|
||||||
['🌤️', 'sun behind small cloud'],
|
|
||||||
['⛅', 'sun behind cloud'],
|
['⛅', 'sun behind cloud'],
|
||||||
['🌥️', 'sun behind large cloud'],
|
|
||||||
['🌦️', 'sun behind rain cloud'],
|
|
||||||
['🌧️', 'cloud with rain'],
|
['🌧️', 'cloud with rain'],
|
||||||
['🌨️', 'cloud with snow'],
|
['🌨️', 'cloud with snow'],
|
||||||
['❄️', 'snowflake'],
|
['❄️', 'snowflake'],
|
||||||
@ -72,14 +61,9 @@ function get_emojis_with_labels(): array {
|
|||||||
['🌊', 'water wave'],
|
['🌊', 'water wave'],
|
||||||
['🌫️', 'fog'],
|
['🌫️', 'fog'],
|
||||||
['🌬️', 'wind face'],
|
['🌬️', 'wind face'],
|
||||||
['🍃', 'leaf fluttering in wind'],
|
|
||||||
['🍂', 'fallen leaf'],
|
['🍂', 'fallen leaf'],
|
||||||
['🍁', 'maple leaf'],
|
|
||||||
['🌾', 'sheaf of rice'],
|
|
||||||
['🌵', 'cactus'],
|
['🌵', 'cactus'],
|
||||||
['🌴', 'palm tree'],
|
['🌴', 'palm tree'],
|
||||||
['🌳', 'deciduous tree'],
|
|
||||||
['🌲', 'evergreen tree'],
|
|
||||||
['🌸', 'cherry blossom'],
|
['🌸', 'cherry blossom'],
|
||||||
],
|
],
|
||||||
'animals' => [
|
'animals' => [
|
||||||
@ -98,45 +82,14 @@ function get_emojis_with_labels(): array {
|
|||||||
['🐷', 'pig face'],
|
['🐷', 'pig face'],
|
||||||
['🐸', 'frog face'],
|
['🐸', 'frog face'],
|
||||||
['🐵', 'monkey face'],
|
['🐵', 'monkey face'],
|
||||||
['🙈', 'see-no-evil monkey'],
|
|
||||||
['🙉', 'hear-no-evil monkey'],
|
|
||||||
['🙊', 'speak-no-evil monkey'],
|
|
||||||
['🐔', 'chicken'],
|
['🐔', 'chicken'],
|
||||||
['🐧', 'penguin'],
|
['🐧', 'penguin'],
|
||||||
['🐦', 'bird'],
|
['🐦', 'bird'],
|
||||||
['🐤', 'baby chick'],
|
|
||||||
['🐣', 'hatching chick'],
|
['🐣', 'hatching chick'],
|
||||||
['🐺', 'wolf face'],
|
['🐺', 'wolf face'],
|
||||||
['🦄', 'unicorn face'],
|
['🦄', 'unicorn face'],
|
||||||
],
|
],
|
||||||
'people' => [
|
'hearts' => [
|
||||||
['🧑', 'person'],
|
|
||||||
['👩', 'woman'],
|
|
||||||
['👨', 'man'],
|
|
||||||
['👶', 'baby'],
|
|
||||||
['👧', 'girl'],
|
|
||||||
['👦', 'boy'],
|
|
||||||
['🧒', 'child'],
|
|
||||||
['👵', 'older woman'],
|
|
||||||
['👴', 'older man'],
|
|
||||||
['🧓', 'older adult'],
|
|
||||||
['👲', 'person with skullcap'],
|
|
||||||
['🧕', 'woman with headscarf'],
|
|
||||||
['👳', 'person wearing turban'],
|
|
||||||
['👮', 'police officer'],
|
|
||||||
['🕵️', 'detective'],
|
|
||||||
['👷', 'construction worker'],
|
|
||||||
['💂', 'guard'],
|
|
||||||
['👸', 'princess'],
|
|
||||||
['🤴', 'prince'],
|
|
||||||
['🦸', 'superhero'],
|
|
||||||
['🦹', 'supervillain'],
|
|
||||||
['🧙', 'mage'],
|
|
||||||
['🧛', 'vampire'],
|
|
||||||
['🧟', 'zombie'],
|
|
||||||
['🧞', 'genie'],
|
|
||||||
],
|
|
||||||
'emotions' => [
|
|
||||||
['❤️', 'red heart'],
|
['❤️', 'red heart'],
|
||||||
['🧡', 'orange heart'],
|
['🧡', 'orange heart'],
|
||||||
['💛', 'yellow heart'],
|
['💛', 'yellow heart'],
|
||||||
@ -155,49 +108,32 @@ function get_emojis_with_labels(): array {
|
|||||||
['💝', 'heart with ribbon'],
|
['💝', 'heart with ribbon'],
|
||||||
['💔', 'broken heart'],
|
['💔', 'broken heart'],
|
||||||
['❣️', 'heart exclamation'],
|
['❣️', 'heart exclamation'],
|
||||||
['💟', 'heart decoration'],
|
|
||||||
['💤', 'zzz'],
|
|
||||||
['🤯', 'exploding head'],
|
|
||||||
['😱', 'face screaming in fear'],
|
|
||||||
['🥵', 'hot face'],
|
|
||||||
['🥶', 'cold face'],
|
|
||||||
['🤬', 'face with symbols on mouth'],
|
|
||||||
],
|
],
|
||||||
'activities' => [
|
'activities' => [
|
||||||
['🚴', 'person biking'],
|
['🚴', 'person biking'],
|
||||||
['🚵', 'person mountain biking'],
|
['🚵', 'person mountain biking'],
|
||||||
['🏃', 'person running'],
|
['🏃', 'person running'],
|
||||||
['🏃♀️', 'woman running'],
|
|
||||||
['🏋️', 'person lifting weights'],
|
['🏋️', 'person lifting weights'],
|
||||||
['🏊', 'person swimming'],
|
['🏊', 'person swimming'],
|
||||||
['🏄', 'person surfing'],
|
['🏄', 'person surfing'],
|
||||||
['🚣', 'person rowing boat'],
|
['🚣', 'person rowing boat'],
|
||||||
['🤽', 'person playing water polo'],
|
|
||||||
['🤾', 'person playing handball'],
|
|
||||||
['⛹️', 'person bouncing ball'],
|
|
||||||
['🤸', 'person cartwheeling'],
|
['🤸', 'person cartwheeling'],
|
||||||
['🧘', 'person in lotus position'],
|
['🧘', 'person in lotus position'],
|
||||||
['🏇', 'horse racing'],
|
|
||||||
['🧗', 'person climbing'],
|
['🧗', 'person climbing'],
|
||||||
['🏕️', 'camping'],
|
['🏕️', 'camping'],
|
||||||
['🎣', 'fishing pole'],
|
['🎣', 'fishing pole'],
|
||||||
['⛺', 'tent'],
|
|
||||||
['🎿', 'skis'],
|
['🎿', 'skis'],
|
||||||
['🏂', 'snowboarder'],
|
['🏂', 'snowboarder'],
|
||||||
['🛹', 'skateboard'],
|
['🛹', 'skateboard'],
|
||||||
['🛼', 'roller skate'],
|
|
||||||
['🧺', 'basket'],
|
['🧺', 'basket'],
|
||||||
['🎯', 'bullseye'],
|
['🎯', 'bullseye'],
|
||||||
['🏌️', 'person golfing'],
|
|
||||||
],
|
],
|
||||||
'hobbies' => [
|
'hobbies' => [
|
||||||
['📚', 'books'],
|
['📚', 'books'],
|
||||||
['📖', 'open book'],
|
['📖', 'open book'],
|
||||||
['🎧', 'headphone'],
|
['🎧', 'headphone'],
|
||||||
['🎵', 'musical note'],
|
['🎵', 'musical note'],
|
||||||
['🎶', 'musical notes'],
|
|
||||||
['🎤', 'microphone'],
|
['🎤', 'microphone'],
|
||||||
['🎼', 'musical score'],
|
|
||||||
['🎷', 'saxophone'],
|
['🎷', 'saxophone'],
|
||||||
['🎸', 'guitar'],
|
['🎸', 'guitar'],
|
||||||
['🎹', 'musical keyboard'],
|
['🎹', 'musical keyboard'],
|
||||||
@ -205,71 +141,14 @@ function get_emojis_with_labels(): array {
|
|||||||
['🎻', 'violin'],
|
['🎻', 'violin'],
|
||||||
['🪕', 'banjo'],
|
['🪕', 'banjo'],
|
||||||
['✍️', 'writing hand'],
|
['✍️', 'writing hand'],
|
||||||
['🖊️', 'pen'],
|
|
||||||
['📝', 'memo'],
|
['📝', 'memo'],
|
||||||
['📷', 'camera'],
|
['📷', 'camera'],
|
||||||
['📸', 'camera with flash'],
|
|
||||||
['🎨', 'artist palette'],
|
['🎨', 'artist palette'],
|
||||||
['🧵', 'thread'],
|
['🧵', 'thread'],
|
||||||
['🧶', 'yarn'],
|
['🧶', 'yarn'],
|
||||||
['🪡', 'sewing needle'],
|
['🪡', 'sewing needle'],
|
||||||
['📹', 'video camera'],
|
['📹', 'video camera'],
|
||||||
['🎬', 'clapper board'],
|
['🎬', 'clapper board'],
|
||||||
['🧩', 'puzzle piece'],
|
|
||||||
],
|
|
||||||
'tech' => [
|
|
||||||
['💻', 'laptop'],
|
|
||||||
['🖥️', 'desktop computer'],
|
|
||||||
['🖨️', 'printer'],
|
|
||||||
['🖱️', 'computer mouse'],
|
|
||||||
['⌨️', 'keyboard'],
|
|
||||||
['📱', 'mobile phone'],
|
|
||||||
['📲', 'mobile phone with arrow'],
|
|
||||||
['📞', 'telephone receiver'],
|
|
||||||
['☎️', 'telephone'],
|
|
||||||
['📟', 'pager'],
|
|
||||||
['📠', 'fax machine'],
|
|
||||||
['🔋', 'battery'],
|
|
||||||
['🔌', 'electric plug'],
|
|
||||||
['💽', 'computer disk'],
|
|
||||||
['💾', 'floppy disk'],
|
|
||||||
['💿', 'optical disk'],
|
|
||||||
['📀', 'dvd'],
|
|
||||||
['🧮', 'abacus'],
|
|
||||||
['🕹️', 'joystick'],
|
|
||||||
['📡', 'satellite antenna'],
|
|
||||||
['🔍', 'magnifying glass tilted left'],
|
|
||||||
['🔎', 'magnifying glass tilted right'],
|
|
||||||
['🧭', 'compass'],
|
|
||||||
['📊', 'bar chart'],
|
|
||||||
['📈', 'chart increasing'],
|
|
||||||
],
|
|
||||||
'travel' => [
|
|
||||||
['✈️', 'airplane'],
|
|
||||||
['🛫', 'airplane departure'],
|
|
||||||
['🛬', 'airplane arrival'],
|
|
||||||
['🚗', 'automobile'],
|
|
||||||
['🚕', 'taxi'],
|
|
||||||
['🚙', 'sport utility vehicle'],
|
|
||||||
['🚌', 'bus'],
|
|
||||||
['🚎', 'trolleybus'],
|
|
||||||
['🏎️', 'racing car'],
|
|
||||||
['🚓', 'police car'],
|
|
||||||
['🚑', 'ambulance'],
|
|
||||||
['🚒', 'fire engine'],
|
|
||||||
['🚐', 'minibus'],
|
|
||||||
['🛻', 'pickup truck'],
|
|
||||||
['🚚', 'delivery truck'],
|
|
||||||
['🚛', 'articulated lorry'],
|
|
||||||
['🚜', 'tractor'],
|
|
||||||
['🚲', 'bicycle'],
|
|
||||||
['🛴', 'kick scooter'],
|
|
||||||
['🚨', 'police car light'],
|
|
||||||
['⛵', 'sailboat'],
|
|
||||||
['🚤', 'speedboat'],
|
|
||||||
['🛳️', 'passenger ship'],
|
|
||||||
['⛴️', 'ferry'],
|
|
||||||
['🚁', 'helicopter'],
|
|
||||||
],
|
],
|
||||||
'food' => [
|
'food' => [
|
||||||
['🍎', 'red apple'],
|
['🍎', 'red apple'],
|
||||||
@ -294,10 +173,34 @@ function get_emojis_with_labels(): array {
|
|||||||
['🍔', 'hamburger'],
|
['🍔', 'hamburger'],
|
||||||
['🍟', 'french fries'],
|
['🍟', 'french fries'],
|
||||||
['🌭', 'hot dog'],
|
['🌭', 'hot dog'],
|
||||||
['🥪', 'sandwich'],
|
|
||||||
['🌮', 'taco'],
|
|
||||||
['🍣', 'sushi'],
|
['🍣', 'sushi'],
|
||||||
],
|
],
|
||||||
|
'vibes' => [
|
||||||
|
['💤', 'zzz'],
|
||||||
|
['🤯', 'exploding head'],
|
||||||
|
['😱', 'face screaming in fear'],
|
||||||
|
['🥵', 'hot face'],
|
||||||
|
['🥶', 'cold face'],
|
||||||
|
['🤬', 'face with symbols on mouth'],
|
||||||
|
['🤨', 'face with raised eyebrow'],
|
||||||
|
],
|
||||||
|
'tech' => [
|
||||||
|
['💻', 'laptop'],
|
||||||
|
['📞', 'telephone receiver'],
|
||||||
|
['🔋', 'battery'],
|
||||||
|
['💿', 'optical disk'],
|
||||||
|
['🕹️', 'joystick'],
|
||||||
|
['🔍', 'magnifying glass tilted left'],
|
||||||
|
['📈', 'chart increasing'],
|
||||||
|
],
|
||||||
|
'travel' => [
|
||||||
|
['✈️', 'airplane'],
|
||||||
|
['🚗', 'automobile'],
|
||||||
|
['🚕', 'taxi'],
|
||||||
|
['🚲', 'bicycle'],
|
||||||
|
['🛴', 'kick scooter'],
|
||||||
|
['⛵', 'sailboat'],
|
||||||
|
],
|
||||||
|
|
||||||
//'custom' => get_user_emojis($db),
|
//'custom' => get_user_emojis($db),
|
||||||
];
|
];
|
||||||
|
@ -1,34 +1,28 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../bootstrap.php';
|
require_once __DIR__ . '/../bootstrap.php';
|
||||||
require_once LIB_ROOT . '/config.php';
|
require_once LIB_ROOT . '/config.php';
|
||||||
|
require_once LIB_ROOT . '/user.php';
|
||||||
|
|
||||||
require LIB_ROOT . '/emoji.php';
|
require LIB_ROOT . '/emoji.php';
|
||||||
|
|
||||||
function get_mood(): ?string {
|
|
||||||
$config = Config::load();
|
|
||||||
$db = get_db();
|
|
||||||
|
|
||||||
$stmt = $db->prepare("SELECT mood FROM user WHERE username=?");
|
|
||||||
$stmt->execute([$_SESSION['username']]);
|
|
||||||
$row = $stmt->fetch();
|
|
||||||
|
|
||||||
return $row['mood'];
|
|
||||||
}
|
|
||||||
|
|
||||||
function save_mood(string $mood): void {
|
function save_mood(string $mood): void {
|
||||||
$config = Config::load();
|
$config = Config::load();
|
||||||
$db = get_db();
|
$user = User::load();
|
||||||
|
//$db = get_db();
|
||||||
|
|
||||||
$stmt = $db->prepare("UPDATE user SET mood=? WHERE username=?");
|
//$stmt = $db->prepare("UPDATE user SET mood=? WHERE username=?");
|
||||||
$stmt->execute([$mood, $_SESSION['username']]);
|
//$stmt->execute([$mood, $_SESSION['username']]);
|
||||||
|
|
||||||
|
$user->mood = $mood;
|
||||||
|
$user = $user->save();
|
||||||
header("Location: $config->basePath");
|
header("Location: $config->basePath");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
function render_emoji_tabs(): string {
|
function render_emoji_tabs(): string {
|
||||||
|
$user = User::load();
|
||||||
$emoji_groups = get_emojis_with_labels();
|
$emoji_groups = get_emojis_with_labels();
|
||||||
$selected_emoji = get_mood();
|
$selected_emoji = $user->mood;
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
?>
|
?>
|
||||||
|
@ -1,20 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../bootstrap.php';
|
require_once __DIR__ . '/../bootstrap.php';
|
||||||
|
|
||||||
function escape_and_linkify_tick(string $tick): string {
|
|
||||||
// escape dangerous characters, but preserve quotes
|
|
||||||
$safe = htmlspecialchars($tick, ENT_NOQUOTES | ENT_HTML5, 'UTF-8');
|
|
||||||
|
|
||||||
// convert URLs to links
|
|
||||||
$safe = preg_replace_callback(
|
|
||||||
'~(https?://[^\s<>"\'()]+)~i',
|
|
||||||
fn($matches) => '<a href="' . htmlspecialchars($matches[1], ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="noopener noreferrer">' . $matches[1] . '</a>',
|
|
||||||
$safe
|
|
||||||
);
|
|
||||||
|
|
||||||
return $safe;
|
|
||||||
}
|
|
||||||
|
|
||||||
function save_tick(string $tick): void {
|
function save_tick(string $tick): void {
|
||||||
// build the tick path and filename from the current time
|
// build the tick path and filename from the current time
|
||||||
$date = new DateTime();
|
$date = new DateTime();
|
||||||
|
@ -9,6 +9,8 @@ class User {
|
|||||||
// properties
|
// properties
|
||||||
public string $username;
|
public string $username;
|
||||||
public string $displayName;
|
public string $displayName;
|
||||||
|
public string $about;
|
||||||
|
public string $website;
|
||||||
public string $mood;
|
public string $mood;
|
||||||
|
|
||||||
// load user settings from sqlite database
|
// load user settings from sqlite database
|
||||||
@ -16,13 +18,15 @@ class User {
|
|||||||
$db = get_db();
|
$db = get_db();
|
||||||
|
|
||||||
// There's only ever one user. I'm just leaning into that.
|
// There's only ever one user. I'm just leaning into that.
|
||||||
$stmt = $db->query("SELECT username, display_name, mood FROM user WHERE id=1");
|
$stmt = $db->query("SELECT username, display_name, about, website, mood FROM user WHERE id=1");
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$u = new self();
|
$u = new self();
|
||||||
|
|
||||||
if ($row) {
|
if ($row) {
|
||||||
$u->username = $row['username'];
|
$u->username = $row['username'];
|
||||||
$u->displayName = $row['display_name'];
|
$u->displayName = $row['display_name'];
|
||||||
|
$u->about = $row['about'] ?? '';
|
||||||
|
$u->website = $row['website'] ?? '';
|
||||||
$u->mood = $row['mood'];
|
$u->mood = $row['mood'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,8 +36,8 @@ class User {
|
|||||||
public function save(): self {
|
public function save(): self {
|
||||||
$db = get_db();
|
$db = get_db();
|
||||||
|
|
||||||
$stmt = $db->prepare("UPDATE user SET username=?, display_name=?, mood=? WHERE id=1");
|
$stmt = $db->prepare("UPDATE user SET username=?, display_name=?, about=?, website=?, mood=? WHERE id=1");
|
||||||
$stmt->execute([$this->username, $this->displayName, $this->mood]);
|
$stmt->execute([$this->username, $this->displayName, $this->about, $this->website, $this->mood]);
|
||||||
|
|
||||||
return self::load();
|
return self::load();
|
||||||
}
|
}
|
||||||
|
15
tkr/lib/util.php
Normal file
15
tkr/lib/util.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function escape_and_linkify(string $text): string {
|
||||||
|
// escape dangerous characters, but preserve quotes
|
||||||
|
$safe = htmlspecialchars($text, ENT_NOQUOTES | ENT_HTML5, 'UTF-8');
|
||||||
|
|
||||||
|
// convert URLs to links
|
||||||
|
$safe = preg_replace_callback(
|
||||||
|
'~(https?://[^\s<>"\'()]+)~i',
|
||||||
|
fn($matches) => '<a href="' . htmlspecialchars($matches[1], ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="noopener noreferrer">' . $matches[1] . '</a>',
|
||||||
|
$safe
|
||||||
|
);
|
||||||
|
|
||||||
|
return $safe;
|
||||||
|
}
|
@ -22,6 +22,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
// User profile
|
// User profile
|
||||||
$username = trim($_POST['username'] ?? '');
|
$username = trim($_POST['username'] ?? '');
|
||||||
$displayName = trim($_POST['display_name'] ?? '');
|
$displayName = trim($_POST['display_name'] ?? '');
|
||||||
|
$about = trim($_POST['about'] ?? '');
|
||||||
|
$website = trim($_POST['website'] ?? '');
|
||||||
|
|
||||||
// Site settings
|
// Site settings
|
||||||
$siteTitle = trim($_POST['site_title']) ?? '';
|
$siteTitle = trim($_POST['site_title']) ?? '';
|
||||||
$siteDescription = trim($_POST['site_description']) ?? '';
|
$siteDescription = trim($_POST['site_description']) ?? '';
|
||||||
@ -40,6 +43,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
if (!$displayName) {
|
if (!$displayName) {
|
||||||
$errors[] = "Display name is required.";
|
$errors[] = "Display name is required.";
|
||||||
}
|
}
|
||||||
|
// Make sure the website looks like a URL and starts with a protocol
|
||||||
|
if ($website) {
|
||||||
|
if (!filter_var($website, FILTER_VALIDATE_URL)) {
|
||||||
|
$errors[] = "Please enter a valid URL (including http:// or https://).";
|
||||||
|
} elseif (!preg_match('/^https?:\/\//i', $website)) {
|
||||||
|
$errors[] = "URL must start with http:// or https://.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Validate site settings
|
// Validate site settings
|
||||||
if (!$siteTitle) {
|
if (!$siteTitle) {
|
||||||
@ -71,6 +83,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
// Update user profile
|
// Update user profile
|
||||||
$user->username = $username;
|
$user->username = $username;
|
||||||
$user->displayName = $displayName;
|
$user->displayName = $displayName;
|
||||||
|
$user->about = $about;
|
||||||
|
$user->website = $website;
|
||||||
|
|
||||||
// Save user profile and reload user from database
|
// Save user profile and reload user from database
|
||||||
$user = $user->save();
|
$user = $user->save();
|
||||||
@ -101,6 +115,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<legend>User settings</legend>
|
<legend>User settings</legend>
|
||||||
<label class="admin-option">Username: <input type="text" name="username" value="<?= $user->username ?>" required></label><br>
|
<label class="admin-option">Username: <input type="text" name="username" value="<?= $user->username ?>" required></label><br>
|
||||||
<label class="admin-option">Display name: <input type="text" name="display_name" value="<?= $user->displayName ?>" required></label><br>
|
<label class="admin-option">Display name: <input type="text" name="display_name" value="<?= $user->displayName ?>" required></label><br>
|
||||||
|
<label class="admin-option">About: <input type="text" name="about" value="<?= $user->about ?>"></label><br>
|
||||||
|
<label class="admin-option">Website: <input type="text" name="website" value="<?= $user->website ?>"></label><br>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset id="site_settings" class="admin-settings-group">
|
<fieldset id="site_settings" class="admin-settings-group">
|
||||||
<legend>Site settings</legend>
|
<legend>Site settings</legend>
|
||||||
|
@ -2,6 +2,28 @@
|
|||||||
|
|
||||||
body { font-family: sans-serif; margin: 2em; }
|
body { font-family: sans-serif; margin: 2em; }
|
||||||
|
|
||||||
|
.flex-container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive layout - makes a one column layout instead of a two-column layout */
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
.flex-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-basis: 200px;
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticks {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.tick { margin-bottom: 1em; }
|
.tick { margin-bottom: 1em; }
|
||||||
|
|
||||||
.ticktime { color: gray; font-size: 0.9em; }
|
.ticktime { color: gray; font-size: 0.9em; }
|
||||||
|
@ -4,11 +4,14 @@ require_once __DIR__ . '/../bootstrap.php';
|
|||||||
confirm_setup();
|
confirm_setup();
|
||||||
|
|
||||||
require_once LIB_ROOT . '/config.php';
|
require_once LIB_ROOT . '/config.php';
|
||||||
|
require_once LIB_ROOT . '/user.php';
|
||||||
require LIB_ROOT . '/session.php';
|
require LIB_ROOT . '/session.php';
|
||||||
require LIB_ROOT . '/ticks.php';
|
require LIB_ROOT . '/ticks.php';
|
||||||
require LIB_ROOT . '/mood.php';
|
require LIB_ROOT . '/util.php';
|
||||||
|
|
||||||
$config = Config::load();
|
$config = Config::load();
|
||||||
|
// I can get away with this before login because there's only one user.
|
||||||
|
$user = User::load();
|
||||||
|
|
||||||
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
|
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
|
||||||
$limit = $config->itemsPerPage;
|
$limit = $config->itemsPerPage;
|
||||||
@ -20,18 +23,43 @@ $ticks = iterator_to_array(stream_ticks($limit, $offset));
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title><?= $config->siteTitle ?></title>
|
<title><?= $config->siteTitle ?></title>
|
||||||
<link rel="stylesheet" href="<?= htmlspecialchars($config->basePath) ?>css/tkr.css">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="<?= htmlspecialchars($config->basePath) ?>css/tkr.css?v=<?= time() ?>">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2><?= $config->siteDescription ?></h2>
|
<h2><?= $config->siteDescription ?></h2>
|
||||||
|
|
||||||
|
<div class="flex-container">
|
||||||
|
<div class="profile">
|
||||||
|
<?php if ($isLoggedIn): ?>
|
||||||
|
<form class="tickform" action="save_tick.php" method="post">
|
||||||
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||||
|
<label for="tick">What's ticking?</label>
|
||||||
|
<input name="tick" id="tick" type="text">
|
||||||
|
<button type="submit">Tick</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
<p>Hi, I'm <?= $user->displayName ?></p>
|
||||||
|
<p><?= $user->about ?></p>
|
||||||
|
<p>Website: <?= escape_and_linkify($user->website) ?></p>
|
||||||
|
<p>Current mood: <?= $user->mood ?></p>
|
||||||
|
<?php if ($isLoggedIn): ?>
|
||||||
|
<a href="<?= $config->basePath ?>set_mood.php">Set your mood</a></p>
|
||||||
|
<p><a href="<?= $config->basePath . '/admin.php' ?>">Admin</a></p>
|
||||||
|
<p><a href="<?= $config->basePath ?>logout.php">Logout</a> <?= htmlspecialchars($user->username) ?> </p>
|
||||||
|
<?php else: ?>
|
||||||
|
<p><a href="<?= $config->basePath ?>login.php">Login</a></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="ticks">
|
||||||
<?php foreach ($ticks as $tick): ?>
|
<?php foreach ($ticks as $tick): ?>
|
||||||
<div class="tick">
|
<div class="tick">
|
||||||
<span class="ticktime"><?= htmlspecialchars($tick['timestamp']) ?></span>
|
<span class="ticktime"><?= htmlspecialchars($tick['timestamp']) ?></span>
|
||||||
<span class="ticktext"><?= escape_and_linkify_tick($tick['tick']) ?></span>
|
<span class="ticktext"><?= escape_and_linkify($tick['tick']) ?></span>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
|
|
||||||
<?php if ($page > 1): ?>
|
<?php if ($page > 1): ?>
|
||||||
@ -40,20 +68,6 @@ $ticks = iterator_to_array(stream_ticks($limit, $offset));
|
|||||||
|
|
||||||
<?php if (count($ticks) === $limit): ?>
|
<?php if (count($ticks) === $limit): ?>
|
||||||
<a href="?page=<?= $page + 1 ?>">Older »</a>
|
<a href="?page=<?= $page + 1 ?>">Older »</a>
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<?php if (!$isLoggedIn): ?>
|
|
||||||
<p><a href="<?= $config->basePath ?>login.php">Login</a></p>
|
|
||||||
<?php else: ?>
|
|
||||||
<form action="save_tick.php" method="post">
|
|
||||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
|
||||||
<label for="tick">What's ticking?</label>
|
|
||||||
<input name="tick" id="tick" type="text">
|
|
||||||
<button type="submit">Tick</button>
|
|
||||||
</form>
|
|
||||||
<p>Current mood: <?= get_mood() ?> | <a href="<?= $config->basePath ?>set_mood.php">Set your mood</a></p>
|
|
||||||
<p><a href="<?= $config->basePath . '/admin.php' ?>">Admin</a> | <a href="<?= $config->basePath ?>logout.php">Logout</a> <?= htmlspecialchars($_SESSION['username']) ?> </p>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
@ -4,6 +4,7 @@ require_once __DIR__ . '/../bootstrap.php';
|
|||||||
require LIB_ROOT . '/config.php';
|
require LIB_ROOT . '/config.php';
|
||||||
require LIB_ROOT . '/session.php';
|
require LIB_ROOT . '/session.php';
|
||||||
require LIB_ROOT . '/ticks.php';
|
require LIB_ROOT . '/ticks.php';
|
||||||
|
require LIB_ROOT . '/util.php';
|
||||||
|
|
||||||
confirm_setup();
|
confirm_setup();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user