📕 yarn is a Self-Hosted, Twitter™-like Decentralised micro-Blogging platform. No ads, no tracking, your content, your data!
https://yarn.social/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
374 lines
16 KiB
374 lines
16 KiB
{{ define "navbar" }} |
|
<div id="podNavigation"{{ if not .Authenticated }} class="mobNoAuth"{{end}}> |
|
{{ if .Authenticated }} |
|
<div id="timelineBtn"> |
|
<a href="/" title="Last updated {{ .TimelineUpdatedAt | time }}"> |
|
<i class="ti ti-message-circle"></i> {{ tr . "NavTimeline" }} |
|
</a> |
|
</div> |
|
<div id="discoverBtn"> |
|
<a href="/discover" title="Last updated {{ .DiscoverUpdatedAt | time }}"> |
|
<i class="ti ti-compass"></i> {{ tr . "NavDiscover" }} |
|
</a> |
|
</div> |
|
<div id="mentionsBtn"> |
|
<a href="/mentions" title="Last mentioned {{ .LastMentionedAt | time }}"> |
|
<i class="ti ti-bell-ringing"></i> {{ tr . "NavMentions" }} |
|
</a> |
|
</div> |
|
<div id="feedsBtn"> |
|
<a href="/feeds"> |
|
<i class="ti ti-rss-nav"></i> {{ tr . "NavFeeds" }} |
|
</a> |
|
</div> |
|
<div id="settingsBtn" > |
|
<a class="secondary" href="/settings"> |
|
<i class="ti ti-settings-nav"></i> {{ tr . "NavSettings" }} |
|
</a> |
|
</div> |
|
<div id="logoutBtn"> |
|
<a class="secondary" href="/logout" onclick="return confirm('{{ tr . "NavLogoutConfirm" }}')"> |
|
<i class="ti ti-door-exit"></i> {{ tr . "NavLogout" }} |
|
</a> |
|
</div> |
|
{{ else }} |
|
<div id="loginBtn"> |
|
<a href="/login"> |
|
<i class="ti ti-door-enter"></i> {{ tr . "NavLogin" }} |
|
</a> |
|
</div> |
|
{{ if not .RegisterDisabled }} |
|
<div id="registerBtn"> |
|
<a href="/register"> |
|
<i class="ti ti-user-plus"></i> {{ tr . "NavRegister" }} |
|
</a> |
|
</div> |
|
{{ end }} |
|
{{ end }} |
|
</div> |
|
<div id="podSearch"{{ if not .Authenticated }} class="mobNoAuth"{{end}}> |
|
<form id="search" action="/search" method="GET"> |
|
<div class="search-grid"> |
|
<input type="search" name="tag" placeholder="Search Tags" aria-label="Search"> |
|
<button type="submit">Search</button> |
|
</div> |
|
</form> |
|
</div> |
|
{{ end }} |
|
|
|
{{ define "post" }} |
|
{{ if $.Authenticated }} |
|
{{ if or (eq $.view "timeline") (eq $.view "bookmarks") }} |
|
<details id="newPost"> |
|
<summary><span><i class="ti ti-message"></i> Create a New Post</span></summary> |
|
{{ end }} |
|
<div id="postbox" class="{{ if eq $.view "permalink" }}single-twt{{ end }}{{ if eq $.view "conv" }}yarn-post{{ end }}"> |
|
<nav id="toolbar" class="toolbar-nav"> |
|
<div class="toolbar-form-button"><a id="bBtn" href="#" title="{{ tr $.Ctx "ToolbarButtonBold" }}" role="button"><i class="ti ti-bold"></i></a></div> |
|
<div class="toolbar-form-button"><a id="iBtn" href="#" title="{{ tr $.Ctx "ToolbarButtonItalic" }}" role="button"><i class="ti ti-italic"></i></a></div> |
|
<div class="toolbar-form-button"><a id="sBtn" href="#" title="{{ tr $.Ctx "ToolbarButtonStrikethrough" }}" role="button"><i class="ti ti-strikethrough"></i></a></div> |
|
<div class="toolbar-form-button"><a id="cBtn" href="#" title="{{ tr $.Ctx "ToolbarButtonCode" }}" role="button"><i class="ti ti-code"></i></a></div> |
|
<div class="toolbar-form-button"><a id="usrBtn" href="#" title="{{ tr $.Ctx "ToolbarButtonMention" }}" role="button"><i class="ti ti-user-circle"></i></a></div> |
|
<div class="toolbar-form-button"><a id="lnkBtn" href="#" title="{{ tr $.Ctx "ToolbarButtonLink" }}" role="button"><i class="ti ti-link"></i></a></div> |
|
<div class="toolbar-form-button"><a id="imgBtn" href="#" title="{{ tr $.Ctx "ToolbarButtonImage" }}" role="button"><i class="ti ti-photo"></i></a></div> |
|
{{ if not $.Ctx.DisableMedia }} |
|
<div class="toolbar-form-button"> |
|
<form id="mediaUploadForm" action="/upload" enctype="multipart/form-data" method="POST" title="{{ tr $.Ctx "ToolbarButtonMedia" }}"> |
|
<input type="hidden" name="csrf_token" value="{{ $.CSRFToken }}"> |
|
<label for="uploadMedia" role="button"><i id="uploadMediaButton" class="ti ti-upload"></i></label> |
|
<input id="uploadMedia" class="invisible width-none" type="file" accept="image/*{{ if not $.Ctx.DisableFfmpeg }},audio/*,video/*{{ end }}" name="media_file" /> |
|
</form> |
|
</div> |
|
{{ end }} |
|
</nav> |
|
<form id="form" class="{{ if eq $.view "conv" }}conv-post{{ end }}" action="/post" method="POST"> |
|
<input type="hidden" name="csrf_token" value="{{ $.CSRFToken }}"> |
|
<input type="hidden" id="replaceTwt" name="hash" value="" /> |
|
<input type="hidden" id="replyTo" name="reply" value="{{ $.Reply }}" /> |
|
<input type="hidden" id="title" name="title" placeholder="{{ tr $.Ctx "TwtFormTitle" }}" value="" /> |
|
<div class="textarea-container"> |
|
<textarea id="text" name="text" placeholder="{{ $.TwtPrompt }}" rows=4 maxlength={{ $.MaxTwtLength }} {{ if $.AutoFocus }}autofocus="true"{{ end }} required="true" aria-required="true">{{ $.PostText }}</textarea> |
|
<div id="mentioned-list" class="users-list"> |
|
<div id="mentioned-list-content" class="mentioned-list-content"> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="submit-bar"> |
|
{{ if gt (len $.User.Feeds) 0 }} |
|
<div> |
|
<select id="postas" class="postas" name="postas"> |
|
<option value="{{ $.User.Username }}" selected>{{ tr $.Ctx "TwtFormPostAs" (dict "Username" $.User.Username) }}</option> |
|
{{ range $index, $feed := $.User.Feeds }} |
|
<option value="{{ $feed }}">{{ $feed }}</option> |
|
{{ end }} |
|
</select> |
|
</div> |
|
{{ end }} |
|
<div> |
|
<button id="post" type="submit"> |
|
<i class="ti ti-send"></i> {{ tr $.Ctx "TwtFormPost" }} |
|
</button> |
|
</div> |
|
</div> |
|
</form> |
|
</div> |
|
{{ if or (eq $.view "timeline") (eq $.view "bookmarks") }} |
|
</details> |
|
{{ end }} |
|
{{ end }} |
|
{{ end }} |
|
|
|
{{ define "twt" }} |
|
<article id="{{ $.Twt.Hash }}" class="h-entry {{ if eq $.view "permalink" }}single-twt{{ end }}"> |
|
<div class="u-author h-card"> |
|
<div> |
|
{{ if $.User.Is $.Twt.Twter.URI }} |
|
<a href="{{ $.User.URL | trimSuffix "/twtxt.txt" }}" class="u-url"> |
|
<img class="avatar u-photo" src="/user/{{ $.User.Username }}/avatar" alt="" loading=lazy /> |
|
</a> |
|
{{ else }} |
|
{{ if isLocalURL $.Twt.Twter.URI }} |
|
<a href="{{ $.Twt.Twter.URI | trimSuffix "/twtxt.txt" }}" class="u-url"> |
|
<img class="avatar u-photo" src="/user/{{ $.Twt.Twter.Nick }}/avatar" alt="" loading=lazy /> |
|
</a> |
|
{{ else }} |
|
<a href="/external?uri={{ $.Twt.Twter.URI }}&nick={{ $.Twt.Twter.Nick }}" class="u-url"> |
|
{{ if $.Twt.Twter.Avatar }} |
|
<img class="avatar u-photo" src="/externalAvatar?uri={{ $.Twt.Twter.URI }}" alt="" loading=lazy /> |
|
{{ else }} |
|
<i class="ti ti-rss" style="font-size:3em"></i> |
|
{{ end }} |
|
</a> |
|
{{ end }} |
|
{{ end }} |
|
</div> |
|
<div class="author"> |
|
<div class="p-name"> |
|
{{ if isLocalURL $.Twt.Twter.URI }} |
|
<a href="{{ $.Twt.Twter.URI | trimSuffix "/twtxt.txt" }}">{{ $.Twt.Twter.Nick }}</a> |
|
{{ else }} |
|
<a href="/external?uri={{ $.Twt.Twter.URI }}&nick={{ $.Twt.Twter.Nick }}">{{ $.Twt.Twter.Nick }}</a> |
|
{{ end }} |
|
</div> |
|
<div class="p-org"> |
|
<a target="_blank" href="{{ $.Twt.Twter.URI | baseFromURL }}">{{ $.Twt.Twter.URI | hostnameFromURL }}</a> |
|
</div> |
|
{{ if not $.User.VisibilityCompact }} |
|
<div class="dt-publish"> |
|
<a class="u-url" href="/twt/{{ $.Twt.Hash }}"> |
|
<time class="dt-published" datetime="{{ $.Twt.Created | date "2006-01-02T15:04:05Z07:00" }}"> |
|
{{ dateInZone (formatForDateTime $.Twt.Created $.User.DisplayTimeFormat) $.Twt.Created $.User.DisplayDatesInTimezone }} |
|
</time> |
|
</a> |
|
<span> ({{ $.Twt.Created | time }})</span> |
|
</div> |
|
{{ end }} |
|
</div> |
|
{{ if $.User.VisibilityCompact }} |
|
<div class="dt-compact"> |
|
<div><a class="u-url" href="/twt/{{ $.Twt.Hash }}">{{ dateInZone (formatForDateTime $.Twt.Created $.User.DisplayTimeFormat) $.Twt.Created $.User.DisplayDatesInTimezone }}</a></div> |
|
<div><small>{{ $.Twt.Created | time }}</small></div> |
|
</div> |
|
{{ end }} |
|
</div> |
|
<div class="e-content"> |
|
{{ if not (eq $.view "conv") }} |
|
{{ with urlForRootConv $.Twt }} |
|
{{ $rootTwt := getRootTwt $.Twt $.User }} |
|
<small class="twt-context"> |
|
↳ |
|
<a href="{{ urlForRootConv $.Twt }}#{{ $.Twt.Hash }}" title="{{ tr $.Ctx "ConversationOnTwtMessage" (dict "Hash" $rootTwt.Hash) }}">{{ tr $.Ctx "ConversationInReply" }}</a> |
|
» |
|
{{ if gt (formatTwtContext $.Twt $.User | len) 0 }} |
|
{{ formatTwtContext $.Twt $.User }} |
|
{{ else }} |
|
<em>This twt is from a user you have muted.</em> |
|
{{ end }} |
|
</small> |
|
{{ end }} |
|
{{ end }} |
|
{{ formatTwt $.Twt $.User }} |
|
</div> |
|
<span id="readtwt">{{ tr $.Ctx "TwtReadMore" }}</span> |
|
<nav class="twt-nav"> |
|
{{ if $.Authenticated }} |
|
<a class="replyBtn" href="#" data-reply="{{ $.User.Reply $.Twt }}"> |
|
<i class="ti ti-message-plus" data-reply="{{ $.User.Reply $.Twt }}"></i> {{ tr $.Ctx "TwtReplyLinkTitle" }} |
|
</a> |
|
{{ if and (eq $.view "conv") (not (eq $.Twt.Hash $.Ctx.Root.Hash)) (lt (getForkLength $.Twt $.User) 1) }} |
|
<a class="forkBtn" href="#" data-fork="{{ $.User.Fork $.Twt }}"> |
|
<i class="ti ti-messages" data-fork="{{ $.User.Fork $.Twt }}"></i> {{ tr $.Ctx "TwtForkLinkTitle" }} |
|
</a> |
|
{{ end }} |
|
{{ if eq $.LastTwt.Hash $.Twt.Hash }} |
|
<a class="editBtn" href="#" data-hash="{{ $.Twt.Hash }}" data-text="{{ $.Twt | unparseTwt }}"> |
|
<i class="ti ti-edit" data-hash="{{ $.Twt.Hash }}" data-text="{{ $.Twt | unparseTwt }}"></i> {{ tr $.Ctx "TwtEditLinkTitle" }} |
|
</a> |
|
<a class="deleteBtn" href="#" data-hash="{{ $.Twt.Hash }}"> |
|
<i class="ti ti-trash" data-hash="{{ $.Twt.Hash }}"></i> {{ tr $.Ctx "TwtDeleteLinkTitle" }} |
|
</a> |
|
{{ end }} |
|
{{ end }} |
|
{{ if and (eq $.view "conv") (not (eq $.Twt.Hash $.Ctx.Root.Hash)) (gt (getForkLength $.Twt $.User) 0) }} |
|
<a class="convBtn" href="{{ urlForFork $.Twt }}"> |
|
<i class="ti ti-messages"></i> {{ tr $.Ctx "TwtForkLinkTitle" }} |
|
<span class="yarn-count-badge">{{ getForkLength $.Twt $.User }}</span> |
|
</a> |
|
{{ end }} |
|
{{ if eq $.Twt.Hash $.Ctx.Root.Hash }} |
|
{{ with urlForRootConv $.Twt }} |
|
<a class="convBtn" href="{{ urlForRootConv $.Twt }}"> |
|
<i class="ti ti-message"></i> {{ tr $.Ctx "ConversationRoot" }} |
|
</a> |
|
{{ end }} |
|
{{ else if not (eq $.view "conv") }} |
|
{{ with urlForConv $.Twt }} |
|
<a class="convBtn" href="{{ urlForConv $.Twt }}"> |
|
<i class="ti ti-message"></i> {{ tr $.Ctx "TwtConversationLinkTitle" }} |
|
{{ if gt (getConvLength $.Twt $.User) 1 }} |
|
<span class="yarn-count-badge">{{ getConvLength $.Twt $.User }}</span> |
|
{{ end }} |
|
</a> |
|
{{ end }} |
|
{{ end }} |
|
{{ if $.Authenticated }} |
|
<div id="twt-options"> |
|
<a class="muteTwtBtn" href="/mute/{{ $.Twt.Hash }}" title="{{ tr $.Ctx "TwtMute" }}"> |
|
<i class="ti ti-volume-3"></i> |
|
</a> |
|
<a class="bookmarkBtn" style="display: {{ if not ($.User.Bookmarked $.Twt.Hash) }}inline{{ else }}none{{ end }};" href="/bookmark/{{ $.Twt.Hash }}" title="{{ tr $.Ctx "BookmarkAddTwt" }}"> |
|
<i class="ti ti-bookmark"></i> |
|
</a> |
|
<a class="unbookmarkBtn" style="display: {{ if ($.User.Bookmarked $.Twt.Hash) }}inline{{ else }}none{{ end }};" href="/bookmark/{{ $.Twt.Hash }}" title="{{ tr $.Ctx "BookmarkRemoveTwt" }}"> |
|
<i class="ti ti-bookmark-off"></i> |
|
</a> |
|
</div> |
|
{{ end }} |
|
</nav> |
|
</article> |
|
{{ end }} |
|
|
|
{{ define "feed" }} |
|
{{ if gt (len $.Twts) 0 }} |
|
<div class="grid h-feed{{ if eq $.view "bookmarks" }} bookmark-feed{{ end }}"> |
|
{{ template "pager" (dict "Pager" $.Pager "Ctx" $.Ctx) }} |
|
{{ range $idx, $twt := $.Twts }} |
|
{{ template "twt" (dict "Authenticated" $.Authenticated "User" $.User "Profile" $.Profile "LastTwt" $.LastTwt "Twt" $twt "Ctx" $.Ctx "view" $.view) }} |
|
{{ else }} |
|
{{ if eq $.view "timeline" }} |
|
<p>{{ tr $.Ctx "NoTwts" }}</p> |
|
<p>{{ tr $.Ctx "ProfileNoTwts" (dict ".InstanceName" $.Ctx.InstanceName ".NavDiscover" (tr $.Ctx "NavDiscover") ".NavFollow" (tr $.Ctx "NavFollow")) | html }}</p> |
|
{{ else }} |
|
<p>{{ .Profile.Nick }} {{ tr $.Ctx "ProfileLastPosted" }} {{ .Profile.LastPostedAt | time }}</p> |
|
{{ end }} |
|
{{ end }} |
|
{{ template "pager" (dict "Pager" $.Pager "Ctx" $.Ctx) }} |
|
</div> |
|
{{ else }} |
|
<div class="h-feed-empty"></div> |
|
{{ end }} |
|
{{ end }} |
|
|
|
{{ define "pager" }} |
|
{{ if $.Pager.HasPages }} |
|
<nav class="{{ if $.Ctx.Root.IsZero }}timeline-nav{{ else }}yarn-nav{{ end }}"> |
|
<ul> |
|
<li> |
|
{{ if $.Pager.HasPrev }} |
|
{{ with $.Ctx.Twter.URI }} |
|
{{ if isLocalURL $.Ctx.Twter.URI }} |
|
<a href="?p={{ $.Pager.PrevPage }}"><i class="ti ti-caret-left"></i> {{ tr $.Ctx "PagerPrevLinkTitle" }}</a> |
|
{{ else }} |
|
<a href="/external?uri={{ $.Ctx.Twter.URI }}&nick={{ $.Ctx.Twter.Nick }}&p={{ $.Pager.PrevPage }}"><i class="ti ti-caret-left"></i> {{ tr $.Ctx "PagerPrevLinkTitle" }}</a> |
|
{{ end }} |
|
{{ else }} |
|
<a href="?p={{ $.Pager.PrevPage }}"><i class="ti ti-caret-left"></i> {{ tr $.Ctx "PagerPrevLinkTitle" }}</a> |
|
{{ end }} |
|
{{ else }} |
|
{{ end }} |
|
</li> |
|
</ul> |
|
<ul> |
|
<li><small>{{ tr $.Ctx "PagerTwtsSummary" (dict "Page" $.Pager.Page "PageNums" $.Pager.PageNums "Nums" $.Pager.Nums) }}</small></li> |
|
</ul> |
|
<ul> |
|
<li> |
|
{{ if $.Pager.HasNext }} |
|
{{ with $.Ctx.Twter.URI }} |
|
{{ if isLocalURL $.Ctx.Twter.URI }} |
|
<a href="?p={{ $.Pager.NextPage }}">{{ tr $.Ctx "PagerNextLinkTitle" }} <i class="ti ti-caret-right"></i></a> |
|
{{ else }} |
|
<a href="/external?uri={{ $.Ctx.Twter.URI }}&nick={{ $.Ctx.Twter.Nick }}&p={{ $.Pager.NextPage }}">{{ tr $.Ctx "PagerNextLinkTitle" }} <i class="ti ti-caret-right"></i></a> |
|
{{ end }} |
|
{{ else }} |
|
<a href="?p={{ $.Pager.NextPage }}">{{ tr $.Ctx "PagerNextLinkTitle" }} <i class="ti ti-caret-right"></i></a> |
|
{{ end }} |
|
{{ else }} |
|
{{ end }} |
|
</li> |
|
</ul> |
|
</nav> |
|
{{ end }} |
|
{{ end }} |
|
|
|
{{ define "followStats" }} |
|
{{ if $.Profile.ShowFollowing }} |
|
<span id="following"> |
|
{{ if eq $.Profile.Type "External" }} |
|
{{ $.Profile.NFollowing }} <a href="/externalFollowing?uri={{ $.Profile.URI }}">{{ tr $.Ctx "ProfileFollowingLinkTitle" }}</a> |
|
{{ else }} |
|
{{ $.Profile.NFollowing }} <a href="/user/{{ $.Profile.Nick }}/following">{{ tr $.Ctx "ProfileFollowingLinkTitle" }}</a> |
|
{{ end }} |
|
</span> |
|
{{ end }} |
|
{{ if $.Profile.ShowFollowers }} |
|
<span id="followers"> |
|
{{ if eq $.Profile.Type "External" }} |
|
{{ $.Profile.NFollowers }} <a href="#" title="{{ tr $.Ctx "FollowExternal" }}">{{ tr $.Ctx "ProfileFollowersLinkTitle" }}</a> |
|
{{ else }} |
|
{{ $.Profile.NFollowers }} <a href="/user/{{ $.Profile.Nick }}/followers">{{ tr $.Ctx "ProfileFollowersLinkTitle" }}</a> |
|
{{ end }} |
|
</span> |
|
{{ end }} |
|
{{ end }} |
|
|
|
{{ define "mutedStats" }} |
|
<div id="muted"> |
|
{{ $.User.Muted | len }} <a href="/muted">{{ tr $.Ctx "MutedLinkTitle" }}</a> |
|
</div> |
|
{{ end }} |
|
|
|
{{ define "profileLinks" }} |
|
<li> |
|
<a target="_blank" href="{{ $.Profile.URI }}"> |
|
<i class="ti ti-link-profile"></i> {{ tr $.Ctx "ProfileTwtxtLinkTitle" }} |
|
</a> |
|
</li> |
|
{{ if ne $.Profile.Type "External" }} |
|
<li> |
|
<a href="{{ $.Profile.URI | trimSuffix "/twtxt.txt" }}/bookmarks"> |
|
<i class="ti ti-bookmarks"></i> {{ tr $.Ctx "ProfileBookmarksLinkTitle" | trimSuffix ":" }} |
|
</a> |
|
</li> |
|
{{ end }} |
|
{{ if $.Profile.Links }} |
|
{{ range $link := $.Profile.Links }} |
|
<li> |
|
<div class="delLink"> |
|
<a href="{{ $link.URL }}"> |
|
<i class="ti ti-external-link"></i> {{ $link.Title }} |
|
</a> |
|
{{ if $.Authenticated }} |
|
{{ if eq $.Profile.Nick $.User.Username }} |
|
<form action="/settings/removelink" enctype="multipart/form-data" method="POST"> |
|
<input type="hidden" name="csrf_token" value="{{ $.CSRFToken }}"> |
|
<input type="hidden" name="link_title" value="{{ $link.Title }}"> |
|
<button type="submit"><i class="ti ti-circle-x"></i></button> |
|
</form> |
|
{{ end }} |
|
{{ end }} |
|
</div> |
|
</li> |
|
{{ end }} |
|
{{ end }} |
|
{{ end }}
|
|
|