Compare commits
8 Commits
5147897c6c
...
e50f12b615
Author | SHA1 | Date |
---|---|---|
r | e50f12b615 | |
r | ad38855261 | |
r | 60ccc9686a | |
r | 60392e61c7 | |
r | 8eec93e028 | |
r | 461908e031 | |
r | 426e9ad14f | |
r | 8a26dd1908 |
|
@ -31,9 +31,6 @@ static_directory=static
|
||||||
# Empty value will disable the format selection in frontend.
|
# Empty value will disable the format selection in frontend.
|
||||||
post_formats=PlainText:text/plain,HTML:text/html,Markdown:text/markdown,BBCode:text/bbcode
|
post_formats=PlainText:text/plain,HTML:text/html,Markdown:text/markdown,BBCode:text/bbcode
|
||||||
|
|
||||||
# Log file. Will log to stdout if value is empty.
|
|
||||||
# log_file=log
|
|
||||||
|
|
||||||
# In single instance mode, bloat will not ask for instance domain name and
|
# In single instance mode, bloat will not ask for instance domain name and
|
||||||
# user will be directly redirected to login form. User login from other
|
# user will be directly redirected to login form. User login from other
|
||||||
# instances is not allowed in this mode.
|
# instances is not allowed in this mode.
|
||||||
|
|
|
@ -20,7 +20,6 @@ type config struct {
|
||||||
TemplatesPath string
|
TemplatesPath string
|
||||||
CustomCSS string
|
CustomCSS string
|
||||||
PostFormats []model.PostFormat
|
PostFormats []model.PostFormat
|
||||||
LogFile string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) IsValid() bool {
|
func (c *config) IsValid() bool {
|
||||||
|
@ -97,7 +96,7 @@ func Parse(r io.Reader) (c *config, err error) {
|
||||||
}
|
}
|
||||||
c.PostFormats = formats
|
c.PostFormats = formats
|
||||||
case "log_file":
|
case "log_file":
|
||||||
c.LogFile = val
|
// ignore
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("invalid config key " + key)
|
return nil, errors.New("invalid config key " + key)
|
||||||
}
|
}
|
||||||
|
|
18
main.go
18
main.go
|
@ -26,6 +26,7 @@ func errExit(err error) {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
configFile := flag.String("f", "", "config file")
|
configFile := flag.String("f", "", "config file")
|
||||||
|
verbose := flag.Bool("v", false, "verbose mode")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if len(*configFile) > 0 {
|
if len(*configFile) > 0 {
|
||||||
|
@ -52,25 +53,12 @@ func main() {
|
||||||
customCSS = "/static/" + customCSS
|
customCSS = "/static/" + customCSS
|
||||||
}
|
}
|
||||||
|
|
||||||
var logger *log.Logger
|
|
||||||
if len(config.LogFile) < 1 {
|
|
||||||
logger = log.New(os.Stdout, "", log.LstdFlags)
|
|
||||||
} else {
|
|
||||||
lf, err := os.OpenFile(config.LogFile,
|
|
||||||
os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
|
||||||
if err != nil {
|
|
||||||
errExit(err)
|
|
||||||
}
|
|
||||||
defer lf.Close()
|
|
||||||
logger = log.New(lf, "", log.LstdFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := service.NewService(config.ClientName, config.ClientScope,
|
s := service.NewService(config.ClientName, config.ClientScope,
|
||||||
config.ClientWebsite, customCSS, config.SingleInstance,
|
config.ClientWebsite, customCSS, config.SingleInstance,
|
||||||
config.PostFormats, renderer)
|
config.PostFormats, renderer)
|
||||||
handler := service.NewHandler(s, logger, config.StaticDirectory)
|
handler := service.NewHandler(s, *verbose, config.StaticDirectory)
|
||||||
|
|
||||||
logger.Println("listening on", config.ListenAddress)
|
log.Println("listening on", config.ListenAddress)
|
||||||
err = http.ListenAndServe(config.ListenAddress, handler)
|
err = http.ListenAndServe(config.ListenAddress, handler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errExit(err)
|
errExit(err)
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
|
|
||||||
// AppConfig is a setting for registering applications.
|
// AppConfig is a setting for registering applications.
|
||||||
type AppConfig struct {
|
type AppConfig struct {
|
||||||
http.Client
|
|
||||||
Server string
|
Server string
|
||||||
ClientName string
|
ClientName string
|
||||||
|
|
||||||
|
@ -62,7 +61,7 @@ func RegisterApp(ctx context.Context, appConfig *AppConfig) (*Application, error
|
||||||
}
|
}
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
resp, err := appConfig.Do(req)
|
resp, err := httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package mastodon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lr struct {
|
||||||
|
io.ReadCloser
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *lr) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = r.ReadCloser.Read(p)
|
||||||
|
// override the generic error returned by the MaxBytesReader
|
||||||
|
if _, ok := err.(*http.MaxBytesError); ok {
|
||||||
|
err = fmt.Errorf("%s \"%s\": response body too large", r.r.Method, r.r.URL)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type transport struct {
|
||||||
|
t http.RoundTripper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *transport) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||||
|
resp, err := t.t.RoundTrip(r)
|
||||||
|
if resp != nil && resp.Body != nil {
|
||||||
|
resp.Body = &lr{http.MaxBytesReader(nil, resp.Body, 8<<20), r}
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpClient = &http.Client{
|
||||||
|
Transport: &transport{
|
||||||
|
t: http.DefaultTransport,
|
||||||
|
},
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
}
|
|
@ -168,12 +168,13 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return json.NewDecoder(resp.Body).Decode(&res)
|
return json.NewDecoder(resp.Body).Decode(&res)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient return new mastodon API client.
|
// NewClient return new mastodon API client.
|
||||||
func NewClient(config *Config) *Client {
|
func NewClient(config *Config) *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
Client: http.DefaultClient,
|
Client: httpClient,
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -68,7 +69,7 @@ func (c *client) redirect(url string) {
|
||||||
c.w.WriteHeader(http.StatusFound)
|
c.w.WriteHeader(http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) authenticate(t int) (err error) {
|
func (c *client) authenticate(t int, instance string) (err error) {
|
||||||
csrf := c.r.FormValue("csrf_token")
|
csrf := c.r.FormValue("csrf_token")
|
||||||
ref := c.r.URL.RequestURI()
|
ref := c.r.URL.RequestURI()
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -98,6 +99,9 @@ func (c *client) authenticate(t int) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.s = sess
|
c.s = sess
|
||||||
|
if len(instance) > 0 && c.s.Instance != instance {
|
||||||
|
return errors.New("invalid instance")
|
||||||
|
}
|
||||||
c.Client = mastodon.NewClient(&mastodon.Config{
|
c.Client = mastodon.NewClient(&mastodon.Config{
|
||||||
Server: "https://" + c.s.Instance,
|
Server: "https://" + c.s.Instance,
|
||||||
ClientID: c.s.ClientID,
|
ClientID: c.s.ClientID,
|
||||||
|
|
|
@ -683,7 +683,7 @@ func (s *service) MutePage(c *client, id string) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cdata := s.cdata(c, "Mute"+user.DisplayName+" @"+user.Acct, 0, 0, "")
|
cdata := s.cdata(c, "Mute "+user.DisplayName+" @"+user.Acct, 0, 0, "")
|
||||||
data := &renderer.UserData{
|
data := &renderer.UserData{
|
||||||
User: user,
|
User: user,
|
||||||
CommonData: cdata,
|
CommonData: cdata,
|
||||||
|
|
|
@ -23,7 +23,7 @@ const (
|
||||||
CSRF
|
CSRF
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler {
|
func NewHandler(s *service, verbose bool, staticDir string) http.Handler {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
|
|
||||||
writeError := func(c *client, err error, t int, retry bool) {
|
writeError := func(c *client, err error, t int, retry bool) {
|
||||||
|
@ -48,10 +48,12 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler {
|
||||||
r: req,
|
r: req,
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(begin time.Time) {
|
if verbose {
|
||||||
logger.Printf("path=%s, err=%v, took=%v\n",
|
defer func(begin time.Time) {
|
||||||
req.URL.Path, err, time.Since(begin))
|
log.Printf("path=%s, err=%v, took=%v\n",
|
||||||
}(time.Now())
|
req.URL.Path, err, time.Since(begin))
|
||||||
|
}(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
var ct string
|
var ct string
|
||||||
switch rt {
|
switch rt {
|
||||||
|
@ -62,7 +64,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler {
|
||||||
}
|
}
|
||||||
c.w.Header().Add("Content-Type", ct)
|
c.w.Header().Add("Content-Type", ct)
|
||||||
|
|
||||||
err = c.authenticate(at)
|
err = c.authenticate(at, s.instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(c, err, rt, req.Method == http.MethodGet)
|
writeError(c, err, rt, req.Method == http.MethodGet)
|
||||||
return
|
return
|
||||||
|
@ -77,7 +79,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
rootPage := handle(func(c *client) error {
|
rootPage := handle(func(c *client) error {
|
||||||
err := c.authenticate(SESSION)
|
err := c.authenticate(SESSION, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errInvalidSession {
|
if err == errInvalidSession {
|
||||||
c.redirect("/signin")
|
c.redirect("/signin")
|
||||||
|
|
|
@ -285,6 +285,12 @@ function onPaste(e) {
|
||||||
fp.files = dt.files;
|
fp.files = dt.files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onKeydown(e) {
|
||||||
|
if (e.key == 'Enter' && e.ctrlKey) {
|
||||||
|
document.querySelector(".post-form").submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
checkCSRFToken();
|
checkCSRFToken();
|
||||||
checkAntiDopamineMode();
|
checkAntiDopamineMode();
|
||||||
|
@ -325,8 +331,10 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var pf = document.querySelector(".post-form")
|
var pf = document.querySelector(".post-form")
|
||||||
if (pf)
|
if (pf) {
|
||||||
pf.addEventListener("paste", onPaste);
|
pf.addEventListener("paste", onPaste);
|
||||||
|
pf.addEventListener("keydown", onKeydown);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// @license-end
|
// @license-end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
body {
|
frame, body {
|
||||||
background-color: #d2d2d2;
|
background-color: #d2d2d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +436,8 @@ img.emoji {
|
||||||
|
|
||||||
.user-list-item {
|
.user-list-item {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
margin: 0 0 12px 0;
|
margin: 0 0 4px 0;
|
||||||
|
padding: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{{with .Data}}
|
{{with .Data}}
|
||||||
{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
|
{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
|
||||||
<div class="page-title"> Mute {{.User.Acct}} </div>
|
<div class="page-title"> Mute {{EmojiFilter (HTML .User.DisplayName) .User.Emojis | Raw}} @{{.User.Acct}} </div>
|
||||||
|
|
||||||
<form action="/mute/{{.User.ID}}" method="POST">
|
<form action="/mute/{{.User.ID}}" method="POST">
|
||||||
<input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
|
<input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="user-info-details-container">
|
<div class="user-info-details-container">
|
||||||
<div class="user-info-details-name">
|
<div class="user-info-details-name">
|
||||||
<bdi class="status-dname"> {{EmojiFilter (HTML .User.DisplayName) .User.Emojis | Raw}} </bdi>
|
<bdi class="status-dname">{{EmojiFilter (HTML .User.DisplayName) .User.Emojis | Raw}}</bdi>
|
||||||
<a class="nav-link" href="/user/{{.User.ID}}" accesskey="0" title="User profile (0)">
|
<a class="nav-link" href="/user/{{.User.ID}}" accesskey="0" title="User profile (0)">
|
||||||
<span class="status-uname"> @{{.User.Acct}} </span>
|
<span class="status-uname">@{{.User.Acct}}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-info-details-nav">
|
<div class="user-info-details-nav">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="notification-follow">
|
<div class="notification-follow">
|
||||||
<div class="notification-info-text">
|
<div class="notification-info-text">
|
||||||
<bdi class="status-dname"> {{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}} </bdi>
|
<bdi class="status-dname">{{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}}</bdi>
|
||||||
<span class="notification-text"> followed you -
|
<span class="notification-text"> followed you -
|
||||||
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="/user/{{.Account.ID}}"> <span class="status-uname"> @{{.Account.Acct}} </span> </a>
|
<a href="/user/{{.Account.ID}}"> <span class="status-uname">@{{.Account.Acct}}</span> </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -48,13 +48,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="notification-follow">
|
<div class="notification-follow">
|
||||||
<div class="notification-info-text">
|
<div class="notification-info-text">
|
||||||
<bdi class="status-dname"> {{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}} </bdi>
|
<bdi class="status-dname">{{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}}</bdi>
|
||||||
<span class="notification-text"> wants to follow you -
|
<span class="notification-text"> wants to follow you -
|
||||||
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="/user/{{.Account.ID}}"> <span class="status-uname"> @{{.Account.Acct}} </span> </a>
|
<a href="/user/{{.Account.ID}}"><span class="status-uname">@{{.Account.Acct}}</span></a>
|
||||||
</div>
|
</div>
|
||||||
<form class="d-inline" action="/accept/{{.Account.ID}}" method="post" target="_self">
|
<form class="d-inline" action="/accept/{{.Account.ID}}" method="post" target="_self">
|
||||||
<input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
|
<input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
<img class="status-profile-img" src="{{.Account.Avatar}}" title="@{{.Account.Acct}}" alt="avatar" height="48" />
|
<img class="status-profile-img" src="{{.Account.Avatar}}" title="@{{.Account.Acct}}" alt="avatar" height="48" />
|
||||||
</a>
|
</a>
|
||||||
<a href="/user/{{.Account.ID}}">
|
<a href="/user/{{.Account.ID}}">
|
||||||
<span class="status-uname"> @{{.Account.Acct}} </span>
|
<span class="status-uname">@{{.Account.Acct}}</span>
|
||||||
</a>
|
</a>
|
||||||
<span class="notification-text"> retweeted your post -
|
<span class="notification-text"> retweeted your post -
|
||||||
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
<img class="status-profile-img" src="{{.Account.Avatar}}" title="@{{.Account.Acct}}" alt="avatar" height="48" />
|
<img class="status-profile-img" src="{{.Account.Avatar}}" title="@{{.Account.Acct}}" alt="avatar" height="48" />
|
||||||
</a>
|
</a>
|
||||||
<a href="/user/{{.Account.ID}}">
|
<a href="/user/{{.Account.ID}}">
|
||||||
<span class="status-uname"> @{{.Account.Acct}} </span>
|
<span class="status-uname">@{{.Account.Acct}}</span>
|
||||||
</a>
|
</a>
|
||||||
<span class="notification-text"> liked your post -
|
<span class="notification-text"> liked your post -
|
||||||
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
||||||
|
@ -107,7 +107,7 @@
|
||||||
<img class="status-profile-img" src="{{.Account.Avatar}}" title="@{{.Account.Acct}}" alt="avatar" height="48" />
|
<img class="status-profile-img" src="{{.Account.Avatar}}" title="@{{.Account.Acct}}" alt="avatar" height="48" />
|
||||||
</a>
|
</a>
|
||||||
<a href="/user/{{.Account.ID}}">
|
<a href="/user/{{.Account.ID}}">
|
||||||
<span class="status-uname"> @{{.Account.Acct}} </span>
|
<span class="status-uname">@{{.Account.Acct}}</span>
|
||||||
</a>
|
</a>
|
||||||
<span class="notification-text"> {{.Type}} -
|
<span class="notification-text"> {{.Type}} -
|
||||||
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
<time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}">{{TimeSince .CreatedAt}}</time>
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="user-list-name">
|
<div class="user-list-name">
|
||||||
<div>
|
<div>
|
||||||
<div class="status-dname"> {{EmojiFilter (HTML .DisplayName) .Emojis | Raw}} </div>
|
<div class="status-dname">{{EmojiFilter (HTML .DisplayName) .Emojis | Raw}}</div>
|
||||||
<a class="img-link" href="/user/{{.ID}}">
|
<a class="img-link" href="/user/{{.ID}}">
|
||||||
<div class="status-uname"> @{{.Acct}} </div>
|
<div class="status-uname">{{.Acct}}</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<form class="d-inline" action="/accept/{{.ID}}" method="post" target="_self">
|
<form class="d-inline" action="/accept/{{.ID}}" method="post" target="_self">
|
||||||
|
|
|
@ -4,14 +4,15 @@
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
||||||
<link rel="icon" type="image/png" href="/static/favicon.png">
|
<link rel="icon" type="image/png" href="/static/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/static/style.css">
|
||||||
<title>{{.Title}}</title>
|
<title>{{.Title}}</title>
|
||||||
</head>
|
</head>
|
||||||
<frameset cols="424px,*">
|
<frameset cols="424px,*">
|
||||||
<frameset rows="316px,*">
|
<frameset rows="316px,*">
|
||||||
<frame name="nav" src="/nav">
|
<frame name="nav" src="/nav" {{if $.Ctx.DarkMode}}class="dark"{{end}}>
|
||||||
<frame name="notification" src="/notifications">
|
<frame name="notification" src="/notifications" {{if $.Ctx.DarkMode}}class="dark"{{end}}>
|
||||||
</frameset>
|
</frameset>
|
||||||
<frame name="main" src="/timeline/home">
|
<frame name="main" src="/timeline/home" {{if $.Ctx.DarkMode}}class="dark"{{end}}>
|
||||||
</frameset>
|
</frameset>
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
<a class="img-link" href="/user/{{.Account.ID}}">
|
<a class="img-link" href="/user/{{.Account.ID}}">
|
||||||
<img class="status-profile-img" src="{{.Account.Avatar}}" title="@{{.Account.Acct}}" alt="avatar" height="24" />
|
<img class="status-profile-img" src="{{.Account.Avatar}}" title="@{{.Account.Acct}}" alt="avatar" height="24" />
|
||||||
</a>
|
</a>
|
||||||
<bdi class="status-dname"> {{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}} </bdi>
|
<bdi class="status-dname">{{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}}</bdi>
|
||||||
<a href="/user/{{.Account.ID}}">
|
<a href="/user/{{.Account.ID}}">
|
||||||
<span class="status-uname"> @{{.Account.Acct}} </span>
|
<span class="status-uname">@{{.Account.Acct}}</span>
|
||||||
</a>
|
</a>
|
||||||
retweeted
|
retweeted
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,9 +23,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<div class="status-name">
|
<div class="status-name">
|
||||||
<bdi class="status-dname"> {{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}} </bdi>
|
<bdi class="status-dname">{{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}}</bdi>
|
||||||
<a href="/user/{{.Account.ID}}">
|
<a href="/user/{{.Account.ID}}">
|
||||||
<span class="status-uname"> @{{.Account.Acct}} </span>
|
<span class="status-uname">@{{.Account.Acct}}</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="more-container">
|
<div class="more-container">
|
||||||
<div class="remote-link">
|
<div class="remote-link">
|
||||||
|
@ -92,8 +92,8 @@
|
||||||
</div>
|
</div>
|
||||||
{{if (or .Content .SpoilerText)}}
|
{{if (or .Content .SpoilerText)}}
|
||||||
<div class="status-content">
|
<div class="status-content">
|
||||||
{{if .SpoilerText}}{{EmojiFilter (HTML .SpoilerText) .Emojis | Raw}}<br/>{{end}}
|
{{- if .SpoilerText}}{{EmojiFilter (HTML .SpoilerText) .Emojis | Raw}}<br/>{{end -}}
|
||||||
{{StatusContentFilter .Content .Emojis .Mentions | Raw}}
|
{{- StatusContentFilter .Content .Emojis .Mentions | Raw -}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .MediaAttachments}}
|
{{if .MediaAttachments}}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
<div class="page-title"> User </div>
|
<div class="page-title"> User </div>
|
||||||
|
|
||||||
<div class="user-info-container">
|
<div class="user-info-container">
|
||||||
<div>
|
|
||||||
<div class="user-profile-img-container">
|
<div class="user-profile-img-container">
|
||||||
<a class="img-link" href="{{.User.Avatar}}" target="_blank">
|
<a class="img-link" href="{{.User.Avatar}}" target="_blank">
|
||||||
<img class="user-profile-img" src="{{.User.Avatar}}" alt="profile-avatar" height="96" />
|
<img class="user-profile-img" src="{{.User.Avatar}}" alt="profile-avatar" height="96" />
|
||||||
|
@ -11,8 +10,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="user-profile-details-container">
|
<div class="user-profile-details-container">
|
||||||
<div>
|
<div>
|
||||||
<bdi class="status-dname"> {{EmojiFilter (HTML .User.DisplayName) .User.Emojis | Raw}} </bdi>
|
<bdi class="status-dname">{{EmojiFilter (HTML .User.DisplayName) .User.Emojis | Raw}}</bdi>
|
||||||
<span class="status-uname"> @{{.User.Acct}} </span>
|
<span class="status-uname">@{{.User.Acct}}</span>
|
||||||
<a class="remote-link" href="{{.User.URL}}" target="_blank" title="remote profile">
|
<a class="remote-link" href="{{.User.URL}}" target="_blank" title="remote profile">
|
||||||
source
|
source
|
||||||
</a>
|
</a>
|
||||||
|
@ -120,17 +119,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-profile-decription">
|
<div class="user-profile-decription">
|
||||||
{{EmojiFilter .User.Note .User.Emojis | Raw}}
|
{{- EmojiFilter .User.Note .User.Emojis | Raw -}}
|
||||||
</div>
|
</div>
|
||||||
{{if .User.Fields}}
|
{{if .User.Fields}}
|
||||||
<div class="user-fields">
|
<div class="user-fields">
|
||||||
{{range .User.Fields}}
|
{{range .User.Fields}}
|
||||||
<div>{{EmojiFilter .Name $.Data.User.Emojis | Raw}} - {{EmojiFilter .Value $.Data.User.Emojis | Raw}}</div>
|
<div>{{- EmojiFilter .Name $.Data.User.Emojis | Raw}} - {{EmojiFilter .Value $.Data.User.Emojis | Raw -}}</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{{if eq .Type ""}}
|
{{if eq .Type ""}}
|
||||||
<div class="page-title"> Statuses </div>
|
<div class="page-title"> Statuses </div>
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-list-name">
|
<div class="user-list-name">
|
||||||
<div class="status-dname"> {{EmojiFilter (HTML .DisplayName) .Emojis | Raw}} </div>
|
<div class="status-dname">{{EmojiFilter (HTML .DisplayName) .Emojis | Raw}}</div>
|
||||||
<a class="img-link" href="/user/{{.ID}}">
|
<a class="img-link" href="/user/{{.ID}}">
|
||||||
<div class="status-uname"> @{{.Acct}} </div>
|
<div class="status-uname">@{{.Acct}}</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue