aboutsummaryrefslogtreecommitdiffhomepage
path: root/templates/actor
diff options
context:
space:
mode:
Diffstat (limited to 'templates/actor')
-rw-r--r--templates/actor/atom.php51
-rw-r--r--templates/actor/avatar.php5
-rw-r--r--templates/actor/profile.php83
-rw-r--r--templates/actor/profile_block_button.php9
-rw-r--r--templates/actor/profile_editable.php40
-rw-r--r--templates/actor/profile_follow_button.php20
-rw-r--r--templates/actor/profile_page.php52
-rw-r--r--templates/actor/profile_pending_follow.php21
-rw-r--r--templates/actor/profile_reset_avatar.php3
-rw-r--r--templates/actor/rss.php46
10 files changed, 330 insertions, 0 deletions
diff --git a/templates/actor/atom.php b/templates/actor/atom.php
new file mode 100644
index 0000000..8bd40fb
--- /dev/null
+++ b/templates/actor/atom.php
@@ -0,0 +1,51 @@
+<?php
+/** @var \Digitigrade\Model\Actor $actor */
+/** @var string $lang */
+
+use Digitigrade\GlobalSettings;
+use Digitigrade\Model\Note;
+use Digitigrade\Model\NotePrivacyScope;
+
+$selfUri = path_to_uri("/actor/$actor->id/feed/$lang/feed.atom");
+$actorPage = path_to_uri("/@/$actor->handle");
+
+echo '<?xml version="1.0" encoding="utf-8"?>';
+?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+ <id><?= $selfUri ?></id>
+ <title>
+ <?= htmlspecialchars($actor->displayName) ?> — <?= GlobalSettings::getInstance()->get('instance.name') ?>
+ </title>
+ <updated><?= Note::findAllWithAuthor($actor, 1)[0]->created->format(DateTime::ATOM) ?></updated>
+ <author>
+ <name><?= htmlspecialchars($actor->displayName) ?></name>
+ <uri><?= $actorPage ?></uri>
+ </author>
+ <link rel="self" href="<?= $selfUri ?>" />
+ <link rel="alternate" type="text/html" href="<?= $actorPage ?>" />
+ <generator version="<?= get_version() ?>">Digitigrade</generator>
+ <?php if (isset($actor->avatar)): ?>
+ <icon><?= $actor->avatar ?></icon>
+ <?php endif; ?>
+ <subtitle><?= __f('user.rss.description', $actor->displayName) ?></subtitle>
+
+ <?php foreach (Note::findAllWithAuthor($actor, limit: 50) as $note): ?>
+ <?php
+ /** @var Note $note */
+ if ($note->privacy->scope != NotePrivacyScope::PUBLIC || $note->inReplyTo != null) {
+ continue;
+ }
+ ?>
+ <entry>
+ <id><?= path_to_uri("/note/$note->id") ?></id>
+ <title><![CDATA[<?= htmlspecialchars(substr($note->plainContent, 0, 50), double_encode: false) ?>]]></title>
+ <updated><?= ($note->modified ?? $note->created)->format(DateTime::ATOM) ?></updated>
+ <link rel="alternate" type="text/html" href="<?= path_to_uri("/@/$actor->handle/note/$note->id") ?>" />
+ <content type="html"><![CDATA[<?= $note->getBestContentAsHtml() ?>]]></content>
+ <?php foreach ($note->attachments as $file): ?>
+ <link rel="enclosure" title="<?= htmlspecialchars($file->description) ?>" type="<?= $file->type ?>"
+ href="<?= $file->href ?>" />
+ <?php endforeach; ?>
+ </entry>
+ <?php endforeach; ?>
+</feed> \ No newline at end of file
diff --git a/templates/actor/avatar.php b/templates/actor/avatar.php
new file mode 100644
index 0000000..16b529b
--- /dev/null
+++ b/templates/actor/avatar.php
@@ -0,0 +1,5 @@
+<?php if (isset($actor->avatar)): ?>
+ <img class="avatar" src="<?= $actor->avatar ?>">
+<?php else: ?>
+ <img class="avatar" src="/static/default-avatar.png">
+<?php endif; ?> \ No newline at end of file
diff --git a/templates/actor/profile.php b/templates/actor/profile.php
new file mode 100644
index 0000000..be27c86
--- /dev/null
+++ b/templates/actor/profile.php
@@ -0,0 +1,83 @@
+<?php
+use Digitigrade\Model\UserAccount;
+use Digitigrade\UserSettings;
+
+$user = UserAccount::findByCurrentSession();
+$actorUser = UserAccount::findByLinkedActor($actor);
+?>
+<div class="fullProfile">
+ <div class="basicInfo">
+
+ <?php if ($addLink ?? false): ?>
+ <a href="/@/<?= $actor->getFullHandle() ?>">
+ <?php endif; ?>
+ <?php call_template('actor/avatar', ['actor' => $actor]); ?>
+ <?php if ($addLink ?? false): ?>
+ </a>
+ <?php endif; ?>
+
+ <div>
+ <div class="displayName"><?= htmlspecialchars($actor->displayName) ?></div>
+ <div class="pronouns"><?= htmlspecialchars($actor->pronouns) ?></div>
+ <div class="handle">@<?= $actor->getFullHandle() ?></div>
+ <div class="joinedDate"><?= sprintf(__('user.profile.createdAt'), $actor->created->format('Y-m-d')) ?>
+ </div>
+ </div>
+
+ <div class="profileMiniActions">
+ <?php call_template('menu_button', [], function () use ($actor, $user, $actorUser) { ?>
+ <?php if (!$actor->isLocal && isset($actor->homepage)): ?>
+ <li>
+ <a href="<?= $actor->homepage ?>" target="_blank">
+ <span class="material-symbols open-in-new"></span>
+ <span><?= __('user.profile.openRemote') ?></span>
+ </a>
+ </li>
+ <?php endif; ?>
+ <?php if ($actorUser != null && (new UserSettings($actorUser))->getBool('profile.rssEnabled')): ?>
+ <?php $lang = get_ui_language(); ?>
+ <li>
+ <a href="<?= "/actor/$actor->id/feed/$lang/feed.rss" ?>" target="_blank" type="application/rss+xml">
+ <span class="material-symbols rss-feed"></span>
+ <span><?= __('user.profile.feed.rss') ?></span>
+ </a>
+ </li>
+ <li>
+ <a href="<?= "/actor/$actor->id/feed/$lang/feed.atom" ?>" target="_blank" type="application/atom+xml">
+ <span class="material-symbols orbit-outline"></span>
+ <span><?= __('user.profile.feed.atom') ?></span>
+ </a>
+ </li>
+ <?php endif; ?>
+ <?php if ($user != null && $user->actor != $actor): ?>
+ <li><?php call_template('actor/profile_block_button', ['user' => $user, 'actor' => $actor]) ?></li>
+ <?php endif; ?>
+ <?php }); ?>
+ </div>
+
+ </div>
+
+ <?php if (isset($actor->bio) && $actor->bio != '') { ?>
+ <pre class="bio"><?= htmlspecialchars($actor->bio) ?></pre>
+ <?php } else {
+ call_template('placeholder_text', ['message' => __('user.profile.bio.placeholder')]);
+ } ?>
+
+ <?php if (isset($user) && $actor->id != $user->actor->id): ?>
+ <div class="profileActions">
+ <?php if ($actor->followsPending($user->actor))
+ call_template('actor/profile_pending_follow', ['subject' => $actor, 'object' => $user->actor]); ?>
+ <?php if ($actor->follows($user->actor)): ?>
+ <?= __('user.profile.followsYou') ?>
+ <?php endif; ?>
+ <?php call_template('actor/profile_follow_button', ['actor' => $actor, 'user' => $user]); ?>
+ </div>
+ <?php elseif ($actor->id == $user->actor->id): ?>
+ <div class="profileActions">
+ <button class="primary" hx-get="/fragment/profile" hx-target="closest .fullProfile" hx-swap="outerHTML">
+ <?= __('form.edit') ?>
+ </button>
+ </div>
+ <?php endif; ?>
+
+</div> \ No newline at end of file
diff --git a/templates/actor/profile_block_button.php b/templates/actor/profile_block_button.php
new file mode 100644
index 0000000..1b71613
--- /dev/null
+++ b/templates/actor/profile_block_button.php
@@ -0,0 +1,9 @@
+<?php
+$blocks = $user->actor->blocks($actor);
+$action = $blocks ? 'unblock' : 'block';
+?>
+<button hx-confirm="<?= __("user.profile.$action.confirm") ?>" hx-post="/fragment/actor/<?= $actor->id ?>/blockButton"
+ hx-swap="outerHTML">
+ <span class="material-symbols <?= $blocks ? 'remove' : 'block' ?>"></span>
+ <span><?= __("user.profile.$action") ?></span>
+</button> \ No newline at end of file
diff --git a/templates/actor/profile_editable.php b/templates/actor/profile_editable.php
new file mode 100644
index 0000000..fc969bd
--- /dev/null
+++ b/templates/actor/profile_editable.php
@@ -0,0 +1,40 @@
+<form class="fullProfile" hx-post="/fragment/profile" hx-swap="outerHTML" enctype="multipart/form-data">
+ <div class="basicInfo">
+ <?php call_template('actor/avatar', ['actor' => $actor]); ?>
+ <div>
+ <div class="row">
+ <div class="column">
+ <label for="profileDisplayName"><?= __('user.profile.displayName') ?></label>
+ <input id="profileDisplayName" name="displayName" type="text" required
+ value="<?= htmlspecialchars($actor->displayName) ?>">
+ </div>
+ <div class="column">
+ <label for="profilePronouns"><?= __('user.profile.pronouns') ?></label>
+ <input id="profilePronouns" name="pronouns" type="text"
+ value="<?= htmlspecialchars($actor->pronouns) ?>">
+ </div>
+ </div>
+ <div class="handle">@<?= $actor->getFullHandle() ?></div>
+ <div class="joinedDate"><?= sprintf(__('user.profile.createdAt'), $actor->created->format('Y-m-d')) ?></div>
+ </div>
+ </div>
+
+ <div class="row">
+ <label for="profileAvatar"><?= __('user.profile.changeAvatar') ?></label>
+ <input style="display: inline-block" type="file" id="profileAvatar" name="avatar" accept="image/*">
+ <?php call_template('actor/profile_reset_avatar'); ?>
+ </div>
+
+ <div class="row">
+ <label for="profileBio"><?= __('user.profile.bio') ?></label>
+ <textarea id="profileBio" name="bio"><?= htmlspecialchars($actor->bio ?? '') ?></textarea>
+ </div>
+
+ <div class="profileActions">
+ <button type="button" class="secondary" hx-get="/fragment/actor/<?= $actor->id ?>"
+ hx-target="closest .fullProfile" hx-swap="outerHTML">
+ <?= __('form.discardChanges') ?>
+ </button>
+ <button class="primary"><?= __('form.saveChanges') ?></button>
+ </div>
+</form> \ No newline at end of file
diff --git a/templates/actor/profile_follow_button.php b/templates/actor/profile_follow_button.php
new file mode 100644
index 0000000..e2b314d
--- /dev/null
+++ b/templates/actor/profile_follow_button.php
@@ -0,0 +1,20 @@
+<?php
+use Digitigrade\Model\FollowRelation;
+use Digitigrade\Model\FollowRelationStatus;
+
+$relation = FollowRelation::findByActors($user->actor, $actor);
+$state = match ($relation?->status) {
+ null => $actor->requestToFollow ? 'request' : 'normal',
+ FollowRelationStatus::PENDING => 'pending',
+ FollowRelationStatus::ACTIVE => 'active'
+};
+?>
+<button class="<?= $state == 'active' ? 'secondary' : 'primary' ?>"
+ hx-post="/fragment/actor/<?= $actor->id ?>/followButton" hx-swap="outerHTML" <?= $state == 'pending' ? 'disabled' : '' ?> hx-disabled-elt="this">
+ <?= __(match ($state) {
+ 'active' => 'user.profile.unfollow.action',
+ 'pending' => 'user.profile.follow.pending',
+ 'request' => 'user.profile.requestToFollow.action',
+ 'normal' => 'user.profile.follow.action'
+ }) ?>
+</button> \ 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..9c11dd6
--- /dev/null
+++ b/templates/actor/profile_page.php
@@ -0,0 +1,52 @@
+<?php
+
+use Digitigrade\Model\Note;
+use Digitigrade\Model\UserAccount;
+use Digitigrade\UserSettings;
+
+$lang = get_ui_language();
+$actorUser = UserAccount::findByLinkedActor($actor);
+
+call_template('skeleton', [
+ 'pageTitle' => "$actor->displayName - @" . $actor->getFullHandle(),
+ 'renderTitleHeading' => false,
+ 'ogTitle' => $actor->displayName,
+ 'ogDesc' => $actor->bio,
+ 'ogImage' => $actor->avatar ?? path_to_uri('/static/default-avatar.png'),
+ 'ogType' => 'profile',
+ 'ogHandle' => '@' . $actor->getFullHandle(true),
+ 'headLinks' => ($actorUser != null && (new UserSettings($actorUser))->getBool('profile.rssEnabled')) ? [
+ [
+ 'rel' => 'alternate',
+ 'type' => 'application/rss+xml',
+ 'href' => "/actor/$actor->id/feed/$lang/feed.rss",
+ 'title' => __('user.profile.feed.rss')
+ ],
+ [
+ 'rel' => 'alternate',
+ 'type' => 'application/atom+xml',
+ 'href' => "/actor/$actor->id/feed/$lang/feed.atom",
+ 'title' => __('user.profile.feed.atom')
+ ]
+ ] : []
+], function () use ($actor) {
+ $user = UserAccount::findByCurrentSession();
+
+ call_template('actor/profile', ['actor' => $actor]);
+ echo '<hr>';
+ $notes = Note::findAllWithAuthor($actor, 20);
+ if (count($notes) == 0) {
+ call_template('placeholder_text', ['message' => __('user.notes.placeholder')]);
+ } elseif ($user != null && $user->actor->blocks($actor)) {
+ call_template('placeholder_text', ['message' => __('user.profile.notesHidden')]);
+ } else {
+ foreach ($notes as $n) {
+ if ($n->isViewableBy($user))
+ call_template('note/note', ['note' => $n]);
+ }
+ $countNotShown = Note::countWithAuthor($actor) - count($notes);
+ if ($countNotShown >= 0) {
+ call_template('placeholder_text', ['count' => $countNotShown]);
+ }
+ }
+}); \ No newline at end of file
diff --git a/templates/actor/profile_pending_follow.php b/templates/actor/profile_pending_follow.php
new file mode 100644
index 0000000..2f49fcd
--- /dev/null
+++ b/templates/actor/profile_pending_follow.php
@@ -0,0 +1,21 @@
+<?php if (isset($response)): ?>
+
+ <div class="pendingInfo">
+ <?= __("followRequests.$response") ?>
+ </div>
+
+<?php else: ?>
+
+ <div class="pendingInfo">
+ <?= __('user.profile.pendingFollowsYou') ?>
+ <button class="primary" hx-post="/fragment/actor/<?= $subject->id ?>/acceptPending" hx-target="closest .pendingInfo"
+ hx-swap="outerHTML">
+ <?= __('followRequests.accept.action') ?>
+ </button>
+ <button class="secondary" hx-post="/fragment/actor/<?= $subject->id ?>/rejectPending"
+ hx-target="closest .pendingInfo" hx-swap="outerHTML">
+ <?= __('followRequests.reject.action') ?>
+ </button>
+ </div>
+
+<?php endif; ?> \ No newline at end of file
diff --git a/templates/actor/profile_reset_avatar.php b/templates/actor/profile_reset_avatar.php
new file mode 100644
index 0000000..86a3507
--- /dev/null
+++ b/templates/actor/profile_reset_avatar.php
@@ -0,0 +1,3 @@
+<button type="button" class="secondary inline" hx-post="/fragment/profile/resetAvatar" <?= ($reset ?? false) ? 'disabled' : '' ?>>
+ <?= __(($reset ?? false) ? 'user.profile.avatarReset' : 'user.profile.resetAvatar') ?>
+</button> \ No newline at end of file
diff --git a/templates/actor/rss.php b/templates/actor/rss.php
new file mode 100644
index 0000000..03fc4f5
--- /dev/null
+++ b/templates/actor/rss.php
@@ -0,0 +1,46 @@
+<?php
+/** @var \Digitigrade\Model\Actor $actor */
+/** @var string $lang */
+
+use Digitigrade\GlobalSettings;
+use Digitigrade\Model\Note;
+use Digitigrade\Model\NotePrivacyScope;
+
+// putting this here because otherwise my ide yells about "shorthand <?"
+// because it thinks i'm trying to do a php thing instead of xml directive
+echo '<?xml version="1.0" encoding="utf-8"?>';
+?>
+<rss version="2.0">
+ <channel>
+ <title>
+ <?= htmlspecialchars($actor->displayName) ?> — <?= GlobalSettings::getInstance()->get('instance.name') ?>
+ </title>
+ <link><?= path_to_uri("/@/$actor->handle") ?></link>
+ <description><?= __f('user.rss.description', htmlspecialchars($actor->displayName)) ?></description>
+ <language><?= $lang ?></language>
+ <generator><?= __f('version', get_version()) ?></generator>
+ <?php if (isset($actor->avatar)): ?>
+ <image>
+ <url><?= $actor->avatar ?></url>
+ </image>
+ <?php endif; ?>
+ <?php foreach (Note::findAllWithAuthor($actor, limit: 50) as $note): ?>
+ <?php
+ /** @var Note $note */
+ if ($note->privacy->scope != NotePrivacyScope::PUBLIC || $note->inReplyTo != null) {
+ continue;
+ }
+ ?>
+ <item>
+ <link><?= path_to_uri("/@/$actor->handle/note/$note->id") ?></link>
+ <guid><?= path_to_uri("/note/$note->id") ?></guid>
+ <title><![CDATA[<?= htmlspecialchars(substr($note->plainContent, 0, 50), double_encode: false) ?>]]></title>
+ <description><![CDATA[<?= $note->getBestContentAsHtml() ?>]]></description>
+ <pubDate><?= $note->created->format(DateTime::RSS) ?></pubDate>
+ <?php foreach ($note->attachments as $file): ?>
+ <enclosure url="<?= $file->href ?>" type="<?= $file->type ?>" size="-1" /><!-- size unknown sorry :( -->
+ <?php endforeach; ?>
+ </item>
+ <?php endforeach; ?>
+ </channel>
+</rss> \ No newline at end of file