diff options
| -rw-r--r-- | Digitigrade/Model.php | 13 | ||||
| -rw-r--r-- | Digitigrade/Model/Actor.php | 4 | ||||
| -rw-r--r-- | Digitigrade/Model/Note.php | 4 | ||||
| -rw-r--r-- | routes/user.php | 29 | ||||
| -rw-r--r-- | static/style.css | 39 | ||||
| -rw-r--r-- | templates/actor_avatar.php | 4 | ||||
| -rw-r--r-- | templates/actor_profile.php | 11 | ||||
| -rw-r--r-- | templates/actor_profile_page.php | 16 | ||||
| -rw-r--r-- | templates/note.php | 12 | ||||
| -rw-r--r-- | templates/skeleton.php | 4 |
10 files changed, 99 insertions, 37 deletions
diff --git a/Digitigrade/Model.php b/Digitigrade/Model.php index 0db27ef..dca1484 100644 --- a/Digitigrade/Model.php +++ b/Digitigrade/Model.php @@ -153,12 +153,21 @@ abstract class Model { return static::fromDbRow($stmt->fetch(\PDO::FETCH_ASSOC)); } - public static function findAllWhere(string $whereClause, array $parameters): array { + public static function findAllWhere( + string $whereClause, + array $parameters, + ?int $limit = null, + int $offset = 0 + ): array { $classNameParts = explode('\\', static::class); $className = $classNameParts[count($classNameParts) - 1]; $tableName = self::mangleName($className); - $stmt = Db::getInstance()->getPdo()->prepare("SELECT * FROM $tableName WHERE $whereClause"); + $query = "SELECT * FROM $tableName WHERE $whereClause"; + if ($limit != null) { + $query .= " LIMIT $limit OFFSET $offset"; + } + $stmt = Db::getInstance()->getPdo()->prepare($query); $stmt->execute($parameters); return array_map(function ($row) { return static::fromDbRow($row); diff --git a/Digitigrade/Model/Actor.php b/Digitigrade/Model/Actor.php index 8059409..d3589ae 100644 --- a/Digitigrade/Model/Actor.php +++ b/Digitigrade/Model/Actor.php @@ -204,6 +204,10 @@ class Actor extends PushableModel implements RpcReceiver { return $instances; } + public function getFullHandle(): string { + return $this->handle . ($this->isLocal ? '' : '@' . hostname_from_uri($this->uri)); + } + public function jsonSerialize(): array { if ($this->deleted) { return [ diff --git a/Digitigrade/Model/Note.php b/Digitigrade/Model/Note.php index 8dbec90..105f475 100644 --- a/Digitigrade/Model/Note.php +++ b/Digitigrade/Model/Note.php @@ -102,8 +102,8 @@ class Note extends PushableModel { return $actors; } - public static function findAllWithAuthor(Actor $author): array { - return self::findAllWhere('author = ?', [$author->id]); + public static function findAllWithAuthor(Actor $author, ?int $limit = null, int $offset = 0): array { + return self::findAllWhere('author = ?', [$author->id], $limit, $offset); } public function getInteractions(): array { diff --git a/routes/user.php b/routes/user.php index 8626c38..c0a632a 100644 --- a/routes/user.php +++ b/routes/user.php @@ -5,26 +5,15 @@ use Digitigrade\Model\Actor; use Digitigrade\Router; Router::getInstance()->mount('/@/:handle', function (array $args) { - $actor = Actor::findLocalByHandle($args['handle']); + if (str_contains($args['handle'], '@')) { + // remote actor + $actor = Actor::findByWebfinger($args['handle']); + } else { + // local actor + $actor = Actor::findLocalByHandle($args['handle']); + } if ($actor == null || $actor->deleted) { - throw new NotFound("i don't know any local user called " . $args['handle']); + throw new NotFound("i don't know any user called " . $args['handle']); } - - ?> - <!DOCTYPE html> - <html> - - <head> - <title><?= $actor->displayName ?> (@<?= $actor->handle ?>)</title> - </head> - - <body> - <h1><?= $actor->displayName ?></h1> - <p>@<?= $actor->handle ?></p> - <hr> - <p><?= $actor->bio ?></p> - </body> - - </html> - <?php + render_template('actor_profile_page', ['actor' => $actor]); });
\ No newline at end of file diff --git a/static/style.css b/static/style.css index 95244cb..fc548fc 100644 --- a/static/style.css +++ b/static/style.css @@ -64,6 +64,11 @@ h1 { padding: 0; } +hr { + border: none; + border-top: 1px solid #5554; +} + article.note { background: #fee4; border: 1px solid #3b005e44; @@ -74,15 +79,15 @@ article.note { grid-template-columns: max-content 1fr; gap: 16px; - img.authorAvatar { + picture.avatar, + picture.avatar > * { width: 64px; aspect-ratio: 1; } .infoLine { display: grid; - grid-auto-columns: max-content 1fr max-content; - grid-auto-flow: column; + grid-template-columns: max-content 1fr max-content; align-items: baseline; margin-bottom: 4px; gap: 8px; @@ -113,3 +118,31 @@ article.note { padding: 0; } } + +.fullProfile { + border-radius: 8px; + margin: 16px; + padding: 16px; + border: 1px solid #23f4; + background: #e6eaff44; + + .basicInfo { + display: grid; + grid-template-columns: max-content 1fr; + gap: 16px; + + picture.avatar, + picture.avatar > * { + width: 96px; + aspect-ratio: 1; + } + .displayName { + font-size: 16pt; + font-weight: bold; + } + .handle, + .joinedDate { + font-size: 10pt; + } + } +} diff --git a/templates/actor_avatar.php b/templates/actor_avatar.php new file mode 100644 index 0000000..d428006 --- /dev/null +++ b/templates/actor_avatar.php @@ -0,0 +1,4 @@ +<picture class="avatar"> + <source srcset="<?= $actor->avatar ?>"> + <img src="/static/default-avatar.svg"> +</picture>
\ No newline at end of file diff --git a/templates/actor_profile.php b/templates/actor_profile.php new file mode 100644 index 0000000..45a0a59 --- /dev/null +++ b/templates/actor_profile.php @@ -0,0 +1,11 @@ +<div class="fullProfile"> + <div class="basicInfo"> + <?php call_template('actor_avatar', ['actor' => $actor]); ?> + <div> + <div class="displayName"><?= $actor->displayName ?></div> + <div class="handle">@<?= $actor->getFullHandle() ?></div> + <div class="joinedDate">Joined on <?= $actor->created->format('Y-m-d') ?></div> + </div> + </div> + <p class="bio"><?= $actor->bio ?></p> +</div>
\ No newline at end of file diff --git a/templates/actor_profile_page.php b/templates/actor_profile_page.php new file mode 100644 index 0000000..e745433 --- /dev/null +++ b/templates/actor_profile_page.php @@ -0,0 +1,16 @@ +<?php + +use Digitigrade\Model\Note; + +call_template('skeleton', [ + 'pageTitle' => "$actor->displayName - @" . $actor->getFullHandle(), + 'renderTitleHeading' => false +], function () { + global $actor; + call_template('actor_profile', ['actor' => $actor]); + echo '<hr>'; + $notes = Note::findAllWithAuthor($actor, 50); + foreach ($notes as $n) { + call_template('note', ['note' => $n]); + } +});
\ No newline at end of file diff --git a/templates/note.php b/templates/note.php index 9c4f609..6fcb477 100644 --- a/templates/note.php +++ b/templates/note.php @@ -1,17 +1,11 @@ -<?php -$fullHandle = $note->author->handle . ($note->author->isLocal ? '' : '@' . hostname_from_uri($note->author->uri)); -?> <article class="note"> - <a href="/@/<?= $fullHandle ?>"> - <picture> - <source srcset="<?= $note->author->avatar ?>"> - <img class="authorAvatar" src="/static/default-avatar.svg"> - </picture> + <a href="/@/<?= $note->author->getFullHandle() ?>"> + <?php call_template('actor_avatar', ['actor' => $note->author]); ?> </a> <div> <div class="infoLine"> <span class="authorName"><?= $note->author->displayName ?></span> - <span class="authorHandle">@<?= $fullHandle ?></span> + <span class="authorHandle">@<?= $note->author->getFullHandle() ?></span> <span class="timestamp"> <?= $note->created->format('Y-m-d \a\t H:i') diff --git a/templates/skeleton.php b/templates/skeleton.php index 8a7fdf1..acf86bf 100644 --- a/templates/skeleton.php +++ b/templates/skeleton.php @@ -18,7 +18,9 @@ </nav> </header> <main> - <h1><?= $pageTitle ?></h1> + <?php if (!isset($renderTitleHeading) || $renderTitleHeading): ?> + <h1><?= $pageTitle ?></h1> + <?php endif; ?> <?php slot(); ?> </main> </body> |
