From d83b62b79c9ead0d3b2ddbf1879fcf0a0531eee2 Mon Sep 17 00:00:00 2001 From: Ty Clifford Date: Fri, 19 Jun 2026 12:03:13 -0400 Subject: [PATCH] - revisit later; avatar, WYSIWYG --- account.php | 98 ++---------------------------------------- admin/settings.php | 6 +-- assets/css/style.css | 16 ++----- business.php | 7 ++- forum.php | 11 +++-- includes/functions.php | 52 ---------------------- 6 files changed, 15 insertions(+), 175 deletions(-) diff --git a/account.php b/account.php index 265696f..97b5f19 100644 --- a/account.php +++ b/account.php @@ -7,7 +7,6 @@ $errors = []; if (isPost()) { csrfCheck(); $em = ps('email'); $pw = ps('password'); $pw2 = ps('password2'); - $avatarPath = (string)($u['avatar_path'] ?? ''); if ($em && !filter_var($em,FILTER_VALIDATE_EMAIL)) $errors[] = 'Invalid email address.'; if ($pw) { if (strlen($pw) < 6) $errors[] = 'Password must be at least 6 characters.'; @@ -15,18 +14,11 @@ if (isPost()) { } if (!$errors && $em && $em !== $u['email'] && qval("SELECT id FROM users WHERE email=? AND id!=?",[$em,uid()])) $errors[] = 'Email already in use.'; if (!$errors) { - if (p('remove_avatar','0') === '1') $avatarPath = ''; - $avatar = storeAvatarUpload('avatar', mbToBytes(setting('avatar_upload_max_mb','3'), 3)); - if (!$avatar['ok']) $errors[] = $avatar['error']; - elseif (!empty($avatar['path'])) $avatarPath = (string)$avatar['path']; - } - if (!$errors) { - if ($pw) qrun("UPDATE users SET email=?,avatar_path=?,password=? WHERE id=?",[$em?:null,$avatarPath,password_hash($pw,PASSWORD_BCRYPT),uid()]); - else qrun("UPDATE users SET email=?,avatar_path=? WHERE id=?",[$em?:null,$avatarPath,uid()]); + if ($pw) qrun("UPDATE users SET email=?,password=? WHERE id=?",[$em?:null,password_hash($pw,PASSWORD_BCRYPT),uid()]); + else qrun("UPDATE users SET email=? WHERE id=?",[$em?:null,uid()]); flash('Account updated successfully!','success'); go('/account.php'); } $u['email'] = $em; - $u['avatar_path'] = $avatarPath; } include __DIR__.'/includes/header.php'; ?> @@ -35,35 +27,13 @@ include __DIR__.'/includes/header.php';

Manage your Discover Keyser WV account

ACCOUNT INFO
-
๐Ÿ‘ค ADMIN':''?>
๐Ÿ“…Joined
๐Ÿ•Last login:
',array_map('e',$errors))?>
-
+ -
- -
- -
- -
- - - -
- - - -
Optional JPG, PNG, GIF, or WebP. Max MB.
- - - -
-
-

CHANGE PASSWORD (leave blank to keep current)

@@ -72,66 +42,4 @@ include __DIR__.'/includes/header.php';
- -(function(){ - const input = document.getElementById('avatarInput'); - const canvas = document.getElementById('avatarCanvas'); - if (!input || !canvas) return; - const ctx = canvas.getContext('2d'); - const zoom = document.getElementById('avatarZoom'); - const fx = document.getElementById('avatarFocusX'); - const fy = document.getElementById('avatarFocusY'); - const cx = document.getElementById('avatarCropX'); - const cy = document.getElementById('avatarCropY'); - const cs = document.getElementById('avatarCropSize'); - let img = null; - - function drawEmpty(){ - ctx.clearRect(0,0,240,240); - ctx.fillStyle = '#121f38'; - ctx.fillRect(0,0,240,240); - ctx.strokeStyle = 'rgba(38,244,255,.35)'; - ctx.lineWidth = 2; - ctx.beginPath(); - ctx.arc(120,120,104,0,Math.PI*2); - ctx.stroke(); - } - function redraw(){ - if (!img) { drawEmpty(); return; } - const z = parseFloat(zoom.value || '1'); - const natural = Math.min(img.naturalWidth, img.naturalHeight); - const size = Math.max(1, Math.round(natural / z)); - const x = Math.round((img.naturalWidth - size) * (parseInt(fx.value,10) / 100)); - const y = Math.round((img.naturalHeight - size) * (parseInt(fy.value,10) / 100)); - cx.value = x; cy.value = y; cs.value = size; - ctx.clearRect(0,0,240,240); - ctx.save(); - ctx.beginPath(); - ctx.arc(120,120,118,0,Math.PI*2); - ctx.clip(); - ctx.drawImage(img, x, y, size, size, 0, 0, 240, 240); - ctx.restore(); - ctx.strokeStyle = 'rgba(255,209,102,.9)'; - ctx.lineWidth = 2; - ctx.beginPath(); - ctx.arc(120,120,118,0,Math.PI*2); - ctx.stroke(); - } - input.addEventListener('change', function(){ - const file = input.files && input.files[0]; - if (!file) { img = null; redraw(); return; } - const reader = new FileReader(); - reader.onload = function(){ - img = new Image(); - img.onload = redraw; - img.src = reader.result; - }; - reader.readAsDataURL(file); - }); - [zoom, fx, fy].forEach(el => el && el.addEventListener('input', redraw)); - drawEmpty(); -})(); - -HTML; ?> diff --git a/admin/settings.php b/admin/settings.php index 7df42b2..4ac98f9 100644 --- a/admin/settings.php +++ b/admin/settings.php @@ -18,7 +18,6 @@ if (isPost()) { setSetting('event_upload_max_mb', (string)max(1, (float)p('event_upload_max_mb','5'))); setSetting('menu_item_image_limit', (string)max(0, min(1, (int)p('menu_item_image_limit','1')))); setSetting('menu_upload_max_mb', (string)max(1, (float)p('menu_upload_max_mb','5'))); - setSetting('avatar_upload_max_mb', (string)max(1, (float)p('avatar_upload_max_mb','3'))); setSetting('forum_image_resize_threshold_mb', (string)max(0.5, (float)p('forum_image_resize_threshold_mb','1'))); setSetting('forum_image_max_width', (string)max(640, min(3200, (int)p('forum_image_max_width','1600')))); setSetting('forum_image_quality', (string)max(40, min(95, (int)p('forum_image_quality','82')))); @@ -68,7 +67,6 @@ $mailgunHasKey = setting('mailgun_api_key','') !== ''; $eventUploadMax = setting('event_upload_max_mb','5'); $menuImageLimit = setting('menu_item_image_limit','1'); $menuUploadMax = setting('menu_upload_max_mb','5'); -$avatarUploadMax = setting('avatar_upload_max_mb','3'); $resizeThreshold = setting('forum_image_resize_threshold_mb','1'); $resizeMaxWidth = setting('forum_image_max_width','1600'); $resizeQuality = setting('forum_image_quality','82'); @@ -148,7 +146,7 @@ include __DIR__.'/admin_header.php';
-
+
@@ -158,7 +156,6 @@ include __DIR__.'/admin_header.php';
-

@@ -182,7 +179,6 @@ include __DIR__.'/admin_header.php'; - diff --git a/assets/css/style.css b/assets/css/style.css index c9ea97f..ca88d0d 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -416,17 +416,7 @@ address{font-style:normal} .text-gold{color:var(--gold)}.text-muted{color:var(--text-m)}.text-dim{color:var(--text-d)} .text-right{text-align:right}.text-center{text-align:center} -/* โ”€โ”€ Avatars / Profile Images โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ -.avatar{display:inline-grid;place-items:center;border-radius:50%;object-fit:cover;flex-shrink:0;border:1px solid rgba(38,244,255,.32);background:linear-gradient(135deg,rgba(38,244,255,.18),rgba(255,79,216,.14));color:var(--cyan-l);font-family:'Oswald',sans-serif;font-weight:600;letter-spacing:.04em;box-shadow:0 0 14px rgba(38,244,255,.08)} -.avatar-xs{width:24px;height:24px;font-size:.7rem} -.avatar-sm{width:38px;height:38px;font-size:.9rem} -.avatar-lg{width:96px;height:96px;font-size:2rem} -.account-avatar-preview{display:flex;justify-content:center;margin:.25rem 0 1rem} -.avatar-upload-grid{display:grid;grid-template-columns:240px 1fr;gap:1rem;align-items:start} -.avatar-canvas{width:240px;height:240px;border-radius:50%;border:1px solid rgba(38,244,255,.34);background:var(--bg4);box-shadow:0 0 22px rgba(38,244,255,.08)} -.avatar-crop-controls{display:grid;gap:.5rem;margin-top:.85rem} -.avatar-crop-controls label{display:grid;gap:.2rem;font-family:'Oswald',sans-serif;font-size:.68rem;letter-spacing:.1em;color:var(--text-d)} -.avatar-crop-controls input[type=range]{width:100%;accent-color:var(--cyan)} +/* โ”€โ”€ Reviews โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ .rev-user{display:flex;align-items:center;gap:.7rem} /* โ”€โ”€ Menu images โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ @@ -438,7 +428,7 @@ address{font-style:normal} /* โ”€โ”€ Forum โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ .forum-layout{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:2rem;align-items:start} .forum-topic-list{display:grid;gap:.8rem} -.forum-topic-row{display:grid;grid-template-columns:38px minmax(0,1fr) auto;gap:.85rem;align-items:center;padding:1rem;background:linear-gradient(180deg,rgba(18,31,56,.86),rgba(9,15,30,.92));border:1px solid rgba(38,244,255,.16);border-radius:var(--r);color:var(--text);transition:all var(--t)} +.forum-topic-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.85rem;align-items:center;padding:1rem;background:linear-gradient(180deg,rgba(18,31,56,.86),rgba(9,15,30,.92));border:1px solid rgba(38,244,255,.16);border-radius:var(--r);color:var(--text);transition:all var(--t)} .forum-topic-row:hover{border-color:rgba(38,244,255,.44);box-shadow:var(--sh-sm);transform:translateY(-1px)} .forum-topic-main{min-width:0} .forum-topic-main strong{display:block;color:var(--text);font-size:1rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} @@ -468,7 +458,7 @@ address{font-style:normal} /* โ”€โ”€ Responsive โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ @media(max-width:1100px){.footer-grid{grid-template-columns:1fr 1fr}.home-hero-grid{grid-template-columns:1fr}.hero-signal{grid-template-columns:1fr 1fr}.signal-card-main{min-height:auto}.about-split{grid-template-columns:1fr}} -@media(max-width:900px){.detail-body{grid-template-columns:1fr}.admin-wrap{grid-template-columns:1fr}.admin-side{position:static;max-height:none;border-right:none;border-bottom:1px solid var(--bdr)}.form-row{grid-template-columns:1fr}.section-head{align-items:flex-start;flex-direction:column}.random-list{grid-template-columns:1fr}.signup-grid,.tier-grid{grid-template-columns:1fr}.home-facts{grid-template-columns:1fr}.forum-layout{grid-template-columns:1fr}.avatar-upload-grid{grid-template-columns:1fr}.evt-image-wrap{width:140px;flex-basis:140px}} +@media(max-width:900px){.detail-body{grid-template-columns:1fr}.admin-wrap{grid-template-columns:1fr}.admin-side{position:static;max-height:none;border-right:none;border-bottom:1px solid var(--bdr)}.form-row{grid-template-columns:1fr}.section-head{align-items:flex-start;flex-direction:column}.random-list{grid-template-columns:1fr}.signup-grid,.tier-grid{grid-template-columns:1fr}.home-facts{grid-template-columns:1fr}.forum-layout{grid-template-columns:1fr}.evt-image-wrap{width:140px;flex-basis:140px}} @media(max-width:768px){ .nav-links{display:none;position:absolute;top:64px;left:0;right:0;background:var(--bg0);border-bottom:1px solid var(--bdr-l);flex-direction:column;padding:.75rem 1rem;gap:.1rem;box-shadow:var(--sh)} .nav-links.open{display:flex}.hamburger{display:flex} diff --git a/business.php b/business.php index 42ac434..0a23a5b 100644 --- a/business.php +++ b/business.php @@ -136,7 +136,7 @@ $pageTitle = e($b['name']).' โ€” Keyser, WV'; $activeNav = 'dir'; $reviews = qall(" - SELECT r.*, u.username, u.avatar_path + SELECT r.*, u.username FROM reviews r JOIN users u ON u.id = r.user_id WHERE r.business_id = ? AND r.is_approved = 1 ORDER BY r.created_at DESC @@ -465,10 +465,9 @@ include __DIR__.'/includes/header.php';
-
-
- +
+
diff --git a/forum.php b/forum.php index 0ded3e8..2562f27 100644 --- a/forum.php +++ b/forum.php @@ -96,7 +96,7 @@ if ($topicSlug === '') { $categories = qall("SELECT * FROM forum_categories WHERE is_active=1 ORDER BY sort_order,name"); $topics = qall(" - SELECT ft.*, fc.name category_name, u.username, u.avatar_path, + SELECT ft.*, fc.name category_name, u.username, (SELECT COUNT(*) FROM forum_replies fr WHERE fr.topic_id=ft.id) AS reply_count, COALESCE((SELECT MAX(fr.created_at) FROM forum_replies fr WHERE fr.topic_id=ft.id), ft.created_at) AS last_activity FROM forum_topics ft @@ -130,7 +130,6 @@ if ($topicSlug === '') {
@@ -241,7 +240,7 @@ include __DIR__.'/includes/header.php';
-
+
#reply-
diff --git a/includes/functions.php b/includes/functions.php index e2a5448..a618e8e 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -312,63 +312,11 @@ function storeMultipleUploads(string $field, string $subdir, array $allowedExts, } return ['ok'=>true, 'files'=>$saved]; } -function storeAvatarUpload(string $field, int $maxBytes): array { - $files = normalizeUploadFiles($field); - if (!$files || ($files[0]['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) return ['ok'=>true, 'path'=>'']; - $file = $files[0]; - if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) return ['ok'=>false, 'error'=>uploadErrorText((int)$file['error'])]; - if ((int)($file['size'] ?? 0) > $maxBytes) return ['ok'=>false, 'error'=>'The avatar exceeds the configured size limit.']; - $ext = strtolower(pathinfo((string)$file['name'], PATHINFO_EXTENSION)); - if (!isImageExt($ext)) return ['ok'=>false, 'error'=>'Please choose a JPG, PNG, GIF, or WebP avatar.']; - - if (!function_exists('getimagesize') || !function_exists('imagecreatetruecolor')) { - return storeUploadedFile($file, 'avatars', imageExts(), $maxBytes, ['image_only'=>true, 'resize_over_bytes'=>mbToBytes(1), 'image_max_width'=>512, 'image_quality'=>86]); - } - $info = @getimagesize((string)$file['tmp_name']); - if (!$info || empty($info[0]) || empty($info[1]) || empty($info['mime'])) return ['ok'=>false, 'error'=>'The selected avatar is not a valid image.']; - $loader = match($info['mime']) { - 'image/jpeg' => 'imagecreatefromjpeg', - 'image/png' => 'imagecreatefrompng', - 'image/gif' => 'imagecreatefromgif', - 'image/webp' => 'imagecreatefromwebp', - default => '', - }; - if ($loader === '' || !function_exists($loader)) return ['ok'=>false, 'error'=>'That avatar image type is not supported by this server.']; - $src = @$loader((string)$file['tmp_name']); - if (!$src) return ['ok'=>false, 'error'=>'The avatar could not be opened.']; - - $w = (int)$info[0]; $h = (int)$info[1]; - $size = (int)p('avatar_crop_size', min($w, $h)); - $x = (int)p('avatar_crop_x', max(0, (int)(($w - $size) / 2))); - $y = (int)p('avatar_crop_y', max(0, (int)(($h - $size) / 2))); - $size = max(1, min($size, $w, $h)); - $x = max(0, min($x, $w - $size)); - $y = max(0, min($y, $h - $size)); - - $dst = imagecreatetruecolor(512, 512); - imagecopyresampled($dst, $src, 0, 0, $x, $y, 512, 512, $size, $size); - $dir = ensureUploadDir('avatars'); - $filename = date('YmdHis').'-'.bin2hex(random_bytes(5)).'.jpg'; - $dest = $dir.'/'.$filename; - $ok = imagejpeg($dst, $dest, 86); - imagedestroy($src); - imagedestroy($dst); - if (!$ok) return ['ok'=>false, 'error'=>'The cropped avatar could not be saved.']; - @chmod($dest, 0664); - return ['ok'=>true, 'path'=>uploadPublicPath('avatars', $filename)]; -} function formatBytes(int $bytes): string { if ($bytes >= 1048576) return number_format($bytes / 1048576, 1).' MB'; if ($bytes >= 1024) return number_format($bytes / 1024, 1).' KB'; return $bytes.' B'; } -function userAvatarHtml(?array $user, string $class = 'avatar-sm'): string { - $name = (string)($user['username'] ?? 'User'); - $path = (string)($user['avatar_path'] ?? ''); - if ($path !== '') return ''.e($name).''; - $initial = strtoupper(substr($name, 0, 1) ?: 'U'); - return ''; -} function uniqueForumSlug(string $title, int $id): string { $base = makeSlug($title) ?: 'topic'; return $base.'-'.$id;