diff options
| -rw-r--r-- | mastodon/status.go | 1 | ||||
| -rw-r--r-- | model/postContext.go | 1 | ||||
| -rw-r--r-- | model/settings.go | 2 | ||||
| -rw-r--r-- | renderer/model.go | 3 | ||||
| -rw-r--r-- | renderer/renderer.go | 42 | ||||
| -rw-r--r-- | service/service.go | 12 | ||||
| -rw-r--r-- | service/transport.go | 2 | ||||
| -rw-r--r-- | static/fluoride.js | 12 | ||||
| -rw-r--r-- | static/main.css | 30 | ||||
| -rw-r--r-- | templates/header.tmpl | 2 | ||||
| -rw-r--r-- | templates/notification.tmpl | 6 | ||||
| -rw-r--r-- | templates/postform.tmpl | 2 | ||||
| -rw-r--r-- | templates/settings.tmpl | 4 | ||||
| -rw-r--r-- | templates/status.tmpl | 26 | ||||
| -rw-r--r-- | templates/user.tmpl | 2 | 
15 files changed, 124 insertions, 23 deletions
| diff --git a/mastodon/status.go b/mastodon/status.go index 06fdd20..e6e247f 100644 --- a/mastodon/status.go +++ b/mastodon/status.go @@ -57,6 +57,7 @@ type Status struct {  	ThreadInNewTab  bool                   `json:"thread_in_new_tab"`  	MaskNSFW        bool                   `json:"mask_nsfw"`  	RetweetedByID   string                 `json:"retweeted_by_id"` +	DarkMode        bool                   `json:"dark_mode"`  }  // Context hold information for mastodon context. diff --git a/model/postContext.go b/model/postContext.go index 3098437..58997f7 100644 --- a/model/postContext.go +++ b/model/postContext.go @@ -9,6 +9,7 @@ type PostContext struct {  	DefaultVisibility string  	ReplyContext      *ReplyContext  	Formats           []PostFormat +	DarkMode          bool  }  type ReplyContext struct { diff --git a/model/settings.go b/model/settings.go index b8eeffc..7d22747 100644 --- a/model/settings.go +++ b/model/settings.go @@ -6,6 +6,7 @@ type Settings struct {  	ThreadInNewTab    bool   `json:"thread_in_new_tab"`  	MaskNSFW          bool   `json:"mask_nfsw"`  	FluorideMode      bool   `json:"fluoride_mode"` +	DarkMode          bool   `json:"dark_mode"`  }  func NewSettings() *Settings { @@ -15,5 +16,6 @@ func NewSettings() *Settings {  		ThreadInNewTab:    false,  		MaskNSFW:          true,  		FluorideMode:      false, +		DarkMode:          false,  	}  } diff --git a/renderer/model.go b/renderer/model.go index 102ce55..64b9946 100644 --- a/renderer/model.go +++ b/renderer/model.go @@ -10,6 +10,7 @@ type HeaderData struct {  	NotificationCount int  	CustomCSS         string  	FluorideMode      bool +	DarkMode          bool  }  type NavbarData struct { @@ -58,6 +59,7 @@ type NotificationData struct {  	Notifications []*mastodon.Notification  	HasNext       bool  	NextLink      string +	DarkMode      bool  }  type UserData struct { @@ -66,6 +68,7 @@ type UserData struct {  	Statuses []*mastodon.Status  	HasNext  bool  	NextLink string +	DarkMode bool  }  type AboutData struct { diff --git a/renderer/renderer.go b/renderer/renderer.go index 4065312..42bffad 100644 --- a/renderer/renderer.go +++ b/renderer/renderer.go @@ -11,6 +11,39 @@ import (  	"mastodon"  ) +var ( +	icons = map[string]string{ +		"envelope":          "/static/icons/envelope.png", +		"dark-envelope":     "/static/icons/dark-envelope.png", +		"globe":             "/static/icons/globe.png", +		"dark-globe":        "/static/icons/dark-globe.png", +		"liked":             "/static/icons/liked.png", +		"dark-liked":        "/static/icons/liked.png", +		"link":              "/static/icons/link.png", +		"dark-link":         "/static/icons/dark-link.png", +		"lock":              "/static/icons/lock.png", +		"dark-lock":         "/static/icons/dark-lock.png", +		"mail-forward":      "/static/icons/mail-forward.png", +		"dark-mail-forward": "/static/icons/dark-mail-forward.png", +		"reply":             "/static/icons/reply.png", +		"dark-reply":        "/static/icons/dark-reply.png", +		"retweet":           "/static/icons/retweet.png", +		"dark-retweet":      "/static/icons/dark-retweet.png", +		"retweeted":         "/static/icons/retweeted.png", +		"dark-retweeted":    "/static/icons/retweeted.png", +		"smile-o":           "/static/icons/smile-o.png", +		"dark-smile-o":      "/static/icons/dark-smile-o.png", +		"star-o":            "/static/icons/star-o.png", +		"dark-star-o":       "/static/icons/dark-star-o.png", +		"star":              "/static/icons/star.png", +		"dark-star":         "/static/icons/dark-star.png", +		"unlock-alt":        "/static/icons/unlock-alt.png", +		"dark-unlock-alt":   "/static/icons/dark-unlock-alt.png", +		"user-plus":         "/static/icons/user-plus.png", +		"dark-user-plus":    "/static/icons/dark-user-plus.png", +	} +) +  type Renderer interface {  	RenderErrorPage(ctx context.Context, writer io.Writer, data *ErrorData)  	RenderHomePage(ctx context.Context, writer io.Writer, data *HomePageData) (err error) @@ -42,6 +75,7 @@ func NewRenderer(templateGlobPattern string) (r *renderer, err error) {  		"TimeSince":               TimeSince,  		"FormatTimeRFC3339":       FormatTimeRFC3339,  		"FormatTimeRFC822":        FormatTimeRFC822, +		"GetIcon":                 GetIcon,  	}).ParseGlob(templateGlobPattern)  	if err != nil {  		return @@ -180,3 +214,11 @@ func FormatTimeRFC3339(t time.Time) string {  func FormatTimeRFC822(t time.Time) string {  	return t.Format(time.RFC822)  } + +func GetIcon(name string, darkMode bool) (icon string) { +	if darkMode { +		name = "dark-" + name +	} +	icon, _ = icons[name] +	return +} diff --git a/service/service.go b/service/service.go index f43c463..b3c2103 100644 --- a/service/service.go +++ b/service/service.go @@ -281,10 +281,12 @@ func (svc *service) ServeTimelinePage(ctx context.Context, client io.Writer,  	for i := range statuses {  		statuses[i].ThreadInNewTab = c.Session.Settings.ThreadInNewTab  		statuses[i].MaskNSFW = c.Session.Settings.MaskNSFW +		statuses[i].DarkMode = c.Session.Settings.DarkMode  		if statuses[i].Reblog != nil {  			statuses[i].Reblog.RetweetedByID = statuses[i].ID  			statuses[i].Reblog.ThreadInNewTab = c.Session.Settings.ThreadInNewTab  			statuses[i].Reblog.MaskNSFW = c.Session.Settings.MaskNSFW +			statuses[i].Reblog.DarkMode = c.Session.Settings.DarkMode  		}  	} @@ -317,6 +319,7 @@ func (svc *service) ServeTimelinePage(ctx context.Context, client io.Writer,  	postContext := model.PostContext{  		DefaultVisibility: c.Session.Settings.DefaultVisibility,  		Formats:           svc.postFormats, +		DarkMode:          c.Session.Settings.DarkMode,  	}  	commonData, err := svc.getCommonData(ctx, client, c, timelineType+" timeline ") @@ -385,6 +388,7 @@ func (svc *service) ServeThreadPage(ctx context.Context, client io.Writer, c *mo  				InReplyToName: status.Account.Acct,  				ReplyContent:  content,  			}, +			DarkMode: c.Session.Settings.DarkMode,  		}  	} @@ -401,6 +405,7 @@ func (svc *service) ServeThreadPage(ctx context.Context, client io.Writer, c *mo  		statuses[i].ShowReplies = true  		statuses[i].ReplyMap = replyMap  		statuses[i].MaskNSFW = c.Session.Settings.MaskNSFW +		statuses[i].DarkMode = c.Session.Settings.DarkMode  		addToReplyMap(replyMap, statuses[i].InReplyToID, statuses[i].ID, i+1)  	} @@ -444,6 +449,7 @@ func (svc *service) ServeNotificationPage(ctx context.Context, client io.Writer,  		if notifications[i].Status != nil {  			notifications[i].Status.CreatedAt = notifications[i].CreatedAt  			notifications[i].Status.MaskNSFW = c.Session.Settings.MaskNSFW +			notifications[i].Status.DarkMode = c.Session.Settings.DarkMode  			switch notifications[i].Type {  			case "reblog", "favourite":  				notifications[i].Status.HideAccountInfo = true @@ -476,6 +482,7 @@ func (svc *service) ServeNotificationPage(ctx context.Context, client io.Writer,  		HasNext:       hasNext,  		NextLink:      nextLink,  		CommonData:    commonData, +		DarkMode:      c.Session.Settings.DarkMode,  	}  	err = svc.renderer.RenderNotificationPage(ctx, client, data)  	if err != nil { @@ -507,8 +514,10 @@ func (svc *service) ServeUserPage(ctx context.Context, client io.Writer, c *mode  	for i := range statuses {  		statuses[i].MaskNSFW = c.Session.Settings.MaskNSFW +		statuses[i].DarkMode = c.Session.Settings.DarkMode  		if statuses[i].Reblog != nil {  			statuses[i].Reblog.MaskNSFW = c.Session.Settings.MaskNSFW +			statuses[i].Reblog.DarkMode = c.Session.Settings.DarkMode  		}  	} @@ -528,6 +537,7 @@ func (svc *service) ServeUserPage(ctx context.Context, client io.Writer, c *mode  		HasNext:    hasNext,  		NextLink:   nextLink,  		CommonData: commonData, +		DarkMode:   c.Session.Settings.DarkMode,  	}  	err = svc.renderer.RenderUserPage(ctx, client, data) @@ -723,6 +733,7 @@ func (svc *service) ServeSearchPage(ctx context.Context, client io.Writer, c *mo  		hasNext = len(results.Statuses) == 20  		for i := range results.Statuses {  			results.Statuses[i].MaskNSFW = c.Session.Settings.MaskNSFW +			results.Statuses[i].DarkMode = c.Session.Settings.DarkMode  		}  	} @@ -827,6 +838,7 @@ func (svc *service) getCommonData(ctx context.Context, client io.Writer, c *mode  		data.HeaderData.NotificationCount = notificationCount  		data.HeaderData.FluorideMode = c.Session.Settings.FluorideMode +		data.HeaderData.DarkMode = c.Session.Settings.DarkMode  	}  	return diff --git a/service/transport.go b/service/transport.go index d89b854..0072f95 100644 --- a/service/transport.go +++ b/service/transport.go @@ -448,12 +448,14 @@ func NewHandler(s Service, staticDir string) http.Handler {  		threadInNewTab := req.FormValue("thread_in_new_tab") == "true"  		maskNSFW := req.FormValue("mask_nsfw") == "true"  		fluorideMode := req.FormValue("fluoride_mode") == "true" +		darkMode := req.FormValue("dark_mode") == "true"  		settings := &model.Settings{  			DefaultVisibility: visibility,  			CopyScope:         copyScope,  			ThreadInNewTab:    threadInNewTab,  			MaskNSFW:          maskNSFW,  			FluorideMode:      fluorideMode, +			DarkMode:      darkMode,  		}  		err := s.SaveSettings(ctx, w, nil, settings) diff --git a/static/fluoride.js b/static/fluoride.js index 25ab4a3..6a1b5fb 100644 --- a/static/fluoride.js +++ b/static/fluoride.js @@ -1,8 +1,12 @@  var actionIcons = {  	"like": "/static/icons/star-o.png", +	"dark-like": "/static/icons/dark-star-o.png",  	"unlike": "/static/icons/liked.png", +	"dark-unlike": "/static/icons/liked.png",  	"retweet": "/static/icons/retweet.png", -	"unretweet": "/static/icons/retweeted.png" +	"dark-retweet": "/static/icons/dark-retweet.png", +	"unretweet": "/static/icons/retweeted.png", +	"dark-unretweet": "/static/icons/retweeted.png"  };  var reverseActions = { @@ -31,7 +35,11 @@ function http(method, url, success, error) {  }  function updateActionForm(id, f, action) { -	f.children[1].src = actionIcons[action]; +	if (Array.from(document.body.classList).indexOf("dark") > -1) { +		f.children[1].src = actionIcons["dark-" + action]; +	} else { +		f.children[1].src = actionIcons[action]; +	}  	f.action = "/" + action + "/" + id;  	f.dataset.action = action;  } diff --git a/static/main.css b/static/main.css index 553c9a2..acbca05 100644 --- a/static/main.css +++ b/static/main.css @@ -99,8 +99,8 @@  }  .status-action a:hover, -.status-action a:hover i { -	opacity: 0.8; +.status-action input:hover { +	opacity: 0.6;  }  .status-action a.status-time { @@ -442,3 +442,29 @@  	z-index: 3;  	margin: 0 8px 0 8px;  } + +.dark { +	background-color: #222222; +	background-image: none; +	color: #eaeaea; +} + +.dark a { +	color: #81a2be; +} + +.dark .status-action a { +	color: #999999; +} + +.dark #post-content { +	background-color: #333333; +	border: 1px solid #444444; +	color: #eaeaea; +} + +.dark #reply-popup, +.dark #reply-to-popup { +	background-color: #222222; +	border-color: #444444; +} diff --git a/templates/header.tmpl b/templates/header.tmpl index d511590..10afe8a 100644 --- a/templates/header.tmpl +++ b/templates/header.tmpl @@ -12,4 +12,4 @@  	<script src="/static/fluoride.js"></script>  	{{end}}  </head> -<body> +<body {{if .DarkMode}}class="dark"{{end}}> diff --git a/templates/notification.tmpl b/templates/notification.tmpl index d68382f..79d6d90 100644 --- a/templates/notification.tmpl +++ b/templates/notification.tmpl @@ -14,7 +14,7 @@  		<div>  			<div class="notification-info-text">  				<span class="status-dname"> {{EmojiFilter .Account.DisplayName .Account.Emojis}} </span>   -				<img class="icon" src="/static/icons/user-plus.png" alt="followed" /> +				<img class="icon" src="{{GetIcon "user-plus" .DarkMode}}" alt="followed" />  				<span> followed you </span>  			</div>  			<div class="notification-follow-uname"> @@ -36,7 +36,7 @@  		<div>  			<div class="notification-info-text">  				<span class="status-dname"> {{EmojiFilter .Account.DisplayName .Account.Emojis}} </span>   -				<img class="icon" src="/static/icons/retweeted.png" alt="retweeted" /> +				<img class="icon" src="{{GetIcon "retweeted" .DarkMode}}" alt="retweeted" />  				<span> retweeted your post </span>  			</div>  			{{template "status" .Status}} @@ -53,7 +53,7 @@  		<div>  			<div class="notification-info-text">  				<span class="status-dname"> {{EmojiFilter .Account.DisplayName .Account.Emojis}} </span>   -				<img class="icon" src="/static/icons/liked.png" alt="liked" /> +				<img class="icon" src="{{GetIcon "liked" .DarkMode}}" alt="liked" />  				<span> liked your post </span>  			</div>  			{{template "status" .Status}} diff --git a/templates/postform.tmpl b/templates/postform.tmpl index 4e2d4a4..ff70eaf 100644 --- a/templates/postform.tmpl +++ b/templates/postform.tmpl @@ -6,7 +6,7 @@  	<label for="post-content" class="post-form-title"> New post </label>  	{{end}}  	<a class="post-form-emoji-link" href="/emojis" target="_blank" title="emoji reference"> -		<img class="icon post-emoji" src="/static/icons/smile-o.png" alt="emojis" /> +		<img class="icon post-emoji" src="{{GetIcon "smile-o" .DarkMode}}" alt="emojis" />  	</a>  	<div class="post-form-content-container">  		<textarea id="post-content" name="content" class="post-content" cols="50" rows="5">{{if .ReplyContext}}{{.ReplyContext.ReplyContent}}{{end}}</textarea> diff --git a/templates/settings.tmpl b/templates/settings.tmpl index d15c47b..06e2a9a 100644 --- a/templates/settings.tmpl +++ b/templates/settings.tmpl @@ -28,6 +28,10 @@  		<input id="fluoride-mode" name="fluoride_mode" type="checkbox" value="true" {{if .Settings.FluorideMode}}checked{{end}}>  		<label for="fluoride-mode"> Enable Fluoride Mode </label>  	</div> +	<div class="settings-form-field"> +		<input id="dark-mode" name="dark_mode" type="checkbox" value="true" {{if .Settings.DarkMode}}checked{{end}}> +		<label for="dark-mode"> Use dark theme </label> +	</div>  	<button type="submit"> Save </button>  </form> diff --git a/templates/status.tmpl b/templates/status.tmpl index 9c9d55d..91d666d 100644 --- a/templates/status.tmpl +++ b/templates/status.tmpl @@ -5,7 +5,7 @@  			<img class="status-profile-img" src="{{.Account.AvatarStatic}}" alt="avatar" />  		</a>  		<span class="status-dname"> {{EmojiFilter .Account.DisplayName .Account.Emojis}} </span>   -		<img class="icon" src="/static/icons/retweeted.png" alt="retweeted" /> +		<img class="icon" src="{{GetIcon "retweeted" .DarkMode}}" alt="retweeted" />  		retweeted  	</div>  	{{template "status" .Reblog}} @@ -28,17 +28,17 @@  				</a>  				<a class="status-visibility">  					{{if eq .Visibility "public"}} -					<img class="icon" src="/static/icons/globe.png" alt="Public" title="Public" /> +					<img class="icon" src="{{GetIcon "globe" .DarkMode}}" alt="Public" title="Public" />  					{{else if eq .Visibility "unlisted"}} -					<img class="icon" src="/static/icons/unlock-alt.png" alt="Unlisted" title="Unlisted" /> +					<img class="icon" src="{{GetIcon "unlock-alt" .DarkMode}}" alt="Unlisted" title="Unlisted" />  					{{else if eq .Visibility "private"}} -					<img class="icon" src="/static/icons/lock.png" alt="Private" title="Private" /> +					<img class="icon" src="{{GetIcon "lock" .DarkMode}}" alt="Private" title="Private" />  					{{else if eq .Visibility "direct"}} -					<img class="icon" src="/static/icons/envelope.png" alt="Direct" title="Direct" /> +					<img class="icon" src="{{GetIcon "envelope" .DarkMode}}" alt="Direct" title="Direct" />  					{{end}}  				</a>  				<a class="remote-link" href="{{.URL}}" target="_blank" title="source"> -					<img class="icon" src="/static/icons/link.png" alt="source" /> +					<img class="icon" src="{{GetIcon "link" .DarkMode}}" alt="source" />  				</a>  			</div>  			{{end}} @@ -46,7 +46,7 @@  				{{if .InReplyToID}}  				<div class="status-reply-to">  					<a class="status-reply-to-link" href="{{if not .ShowReplies}}/thread/{{.InReplyToID}}{{end}}#status-{{.InReplyToID}}">  -						<img class="icon" src="/static/icons/mail-forward.png" alt="reply to" /> reply to {{.Pleroma.InReplyToAccountAcct}}  +						<img class="icon" src="{{GetIcon "mail-forward" .DarkMode}}" alt="reply to" /> reply to {{.Pleroma.InReplyToAccountAcct}}   					</a>  				</div>  				{{if index .ReplyMap .ID}} <span class="status-reply-info-divider"> - </span> {{end}} @@ -93,7 +93,7 @@  			<div class="status-action-container">   				<div class="status-action">  					<a class="status-you" href="/thread/{{.ID}}?reply=true#status-{{.ID}}" title="reply">  -						<img class="icon" src="/static/icons/reply.png" alt="reply" /> +						<img class="icon" src="{{GetIcon "reply" .DarkMode}}" alt="reply" />  					</a>  					<a class="status-reply-count" href="/thread/{{.ID}}#status-{{.ID}}" {{if .ThreadInNewTab}}target="_blank"{{end}}>  						{{DisplayInteractionCount .RepliesCount}} @@ -102,18 +102,18 @@  				<div class="status-action">  					{{if or (eq .Visibility "private") (eq .Visibility "direct")}}  					<a class="status-retweet" title="this status cannot be retweeted">  -						<img class="icon" src="/static/icons/retweet.png" alt="retweet" /> +						<img class="icon" src="{{GetIcon "retweet" .DarkMode}}" alt="retweet" />  					</a>  					{{else}}  					{{if .Reblogged}}  					<form class="status-retweet" data-action="unretweet" action="/unretweet/{{.ID}}" method="post">  						<input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}" /> -						<input type="image" src="/static/icons/retweeted.png" alt="undo retweet" class="icon" title="undo retweet"> +						<input type="image" src="{{GetIcon "retweeted" .DarkMode}}" alt="undo retweet" class="icon" title="undo retweet">  					</form>  					{{else}}  					<form class="status-retweet" data-action="retweet" action="/retweet/{{.ID}}" method="post">  						<input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}" /> -						<input type="image" src="/static/icons/retweet.png" alt="retweet" class="icon" title="retweet"> +						<input type="image" src="{{GetIcon "retweet" .DarkMode}}" alt="retweet" class="icon" title="retweet">  					</form>  					{{end}}  					{{end}} @@ -125,12 +125,12 @@  					{{if .Favourited}}  					<form class="status-like" data-action="unlike" action="/unlike/{{.ID}}" method="post">  						<input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}" /> -						<input type="image" src="/static/icons/liked.png" alt="unlike" class="icon" title="unlike"> +						<input type="image" src="{{GetIcon "liked" .DarkMode}}" alt="unlike" class="icon" title="unlike">  					</form>  					{{else}}  					<form class="status-like" data-action="like" action="/like/{{.ID}}" method="post">  						<input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}" /> -						<input type="image" src="/static/icons/star-o.png" alt="like" class="icon" title="like"> +						<input type="image" src="{{GetIcon "star-o" .DarkMode}}" alt="like" class="icon" title="like">  					</form>  					{{end}}  					<a class="status-like-count" href="/likedby/{{.ID}}" title="click to see the the list">  diff --git a/templates/user.tmpl b/templates/user.tmpl index 53de635..60536bb 100644 --- a/templates/user.tmpl +++ b/templates/user.tmpl @@ -14,7 +14,7 @@  			<span class="status-dname"> {{EmojiFilter .User.DisplayName .User.Emojis}} </span>    			<span class="status-uname"> {{.User.Acct}} </span>  			<a class="remote-link" href="{{.User.URL}}" target="_blank" title="remote profile"> -				<img class="icon" src="/static/icons/link.png" alt="link" /> +				<img class="icon" src="{{GetIcon "link" .DarkMode}}" alt="link" />  			</a>  		</div>  		<div> | 
