diff --git a/.gitignore b/.gitignore
index 6f9b97023..1018351bc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,6 @@
# exclude coverage report
cp.out
+
+# exclude node_modules if installed
+/web/source/node_modules
\ No newline at end of file
diff --git a/README.md b/README.md
index 0af1f3f10..4f607de9f 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
Federated social media software.
-![Sloth logo made by Freepik from www.flaticon.com](./assets/sloth.png)
+![Sloth logo made by Freepik from www.flaticon.com](./web/assets/sloth.png)
GoToSocial is a Fediverse server project, written in Golang. It provides an alternative to existing projects such as [Mastodon](https://joinmastodon.org/), [Pleroma](https://pleroma.social/), [Friendica](https://friendica.net), [PixelFed](https://pixelfed.org/) etc.
diff --git a/cmd/gotosocial/main.go b/cmd/gotosocial/main.go
index 70152dc23..27810a80b 100644
--- a/cmd/gotosocial/main.go
+++ b/cmd/gotosocial/main.go
@@ -118,6 +118,12 @@ func main() {
Value: defaults.TemplateBaseDir,
EnvVars: []string{envNames.TemplateBaseDir},
},
+ &cli.StringFlag{
+ Name: flagNames.AssetBaseDir,
+ Usage: "Directory to serve static assets from, accessible at example.com/assets/",
+ Value: defaults.AssetBaseDir,
+ EnvVars: []string{envNames.AssetBaseDir},
+ },
// ACCOUNTS FLAGS
&cli.BoolFlag{
diff --git a/go.mod b/go.mod
index eab14c9f6..d8ddb3018 100644
--- a/go.mod
+++ b/go.mod
@@ -15,6 +15,7 @@ require (
github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e // indirect
github.com/gin-contrib/cors v1.3.1
github.com/gin-contrib/sessions v0.0.3
+ github.com/gin-contrib/static v0.0.1 // indirect
github.com/gin-gonic/gin v1.7.2
github.com/go-errors/errors v1.4.0 // indirect
github.com/go-fed/activity v1.0.1-0.20210426194615-e0de0863dcc1
diff --git a/go.sum b/go.sum
index 37dadf640..7de538121 100644
--- a/go.sum
+++ b/go.sum
@@ -66,7 +66,10 @@ github.com/gin-contrib/sessions v0.0.3 h1:PoBXki+44XdJdlgDqDrY5nDVe3Wk7wDV/UCOuL
github.com/gin-contrib/sessions v0.0.3/go.mod h1:8C/J6cad3Il1mWYYgtw0w+hqasmpvy25mPkXdOgeB9I=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Swm1U=
+github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
@@ -95,6 +98,7 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I=
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
diff --git a/internal/cliactions/server/server.go b/internal/cliactions/server/server.go
index 74b1c789a..c27ec7fac 100644
--- a/internal/cliactions/server/server.go
+++ b/internal/cliactions/server/server.go
@@ -44,6 +44,7 @@ import (
timelineprocessing "github.com/superseriousbusiness/gotosocial/internal/timeline"
"github.com/superseriousbusiness/gotosocial/internal/transport"
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
+ "github.com/superseriousbusiness/gotosocial/internal/web"
)
var models []interface{} = []interface{}{
@@ -123,6 +124,7 @@ var Start cliactions.GTSAction = func(ctx context.Context, c *config.Config, log
appsModule := app.New(c, processor, log)
followRequestsModule := followrequest.New(c, processor, log)
webfingerModule := webfinger.New(c, processor, log)
+ webBaseModule := web.New(c, processor, log)
usersModule := user.New(c, processor, log)
timelineModule := timeline.New(c, processor, log)
notificationModule := notification.New(c, processor, log)
@@ -143,6 +145,7 @@ var Start cliactions.GTSAction = func(ctx context.Context, c *config.Config, log
authModule,
// now everything else
+ webBaseModule,
accountModule,
instanceModule,
appsModule,
diff --git a/internal/config/config.go b/internal/config/config.go
index 8a5e27a0c..b0263b170 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -170,6 +170,11 @@ func (c *Config) ParseCLIFlags(f KeyedFlags) error {
c.TemplateConfig.BaseDir = f.String(fn.TemplateBaseDir)
}
+ // template flags
+ if c.TemplateConfig.AssetBaseDir == "" || f.IsSet(fn.AssetBaseDir) {
+ c.TemplateConfig.AssetBaseDir = f.String(fn.AssetBaseDir)
+ }
+
// accounts flags
if f.IsSet(fn.AccountsOpenRegistration) {
c.AccountsConfig.OpenRegistration = f.Bool(fn.AccountsOpenRegistration)
@@ -283,6 +288,7 @@ type Flags struct {
DbDatabase string
TemplateBaseDir string
+ AssetBaseDir string
AccountsOpenRegistration string
AccountsApprovalRequired string
@@ -326,6 +332,7 @@ type Defaults struct {
DbDatabase string
TemplateBaseDir string
+ AssetBaseDir string
AccountsOpenRegistration bool
AccountsRequireApproval bool
@@ -371,6 +378,7 @@ func GetFlagNames() Flags {
DbDatabase: "db-database",
TemplateBaseDir: "template-basedir",
+ AssetBaseDir: "asset-basedir",
AccountsOpenRegistration: "accounts-open-registration",
AccountsApprovalRequired: "accounts-approval-required",
@@ -417,6 +425,7 @@ func GetEnvNames() Flags {
DbDatabase: "GTS_DB_DATABASE",
TemplateBaseDir: "GTS_TEMPLATE_BASEDIR",
+ AssetBaseDir: "GTS_ASSET_BASEDIR",
AccountsOpenRegistration: "GTS_ACCOUNTS_OPEN_REGISTRATION",
AccountsApprovalRequired: "GTS_ACCOUNTS_APPROVAL_REQUIRED",
diff --git a/internal/config/default.go b/internal/config/default.go
index f63579753..8a53f239e 100644
--- a/internal/config/default.go
+++ b/internal/config/default.go
@@ -18,7 +18,8 @@ func TestDefault() *Config {
ApplicationName: defaults.ApplicationName,
},
TemplateConfig: &TemplateConfig{
- BaseDir: defaults.TemplateBaseDir,
+ BaseDir: defaults.TemplateBaseDir,
+ AssetBaseDir: defaults.AssetBaseDir,
},
AccountsConfig: &AccountsConfig{
OpenRegistration: defaults.AccountsOpenRegistration,
@@ -71,7 +72,8 @@ func Default() *Config {
ApplicationName: defaults.ApplicationName,
},
TemplateConfig: &TemplateConfig{
- BaseDir: defaults.TemplateBaseDir,
+ BaseDir: defaults.TemplateBaseDir,
+ AssetBaseDir: defaults.AssetBaseDir,
},
AccountsConfig: &AccountsConfig{
OpenRegistration: defaults.AccountsOpenRegistration,
@@ -124,6 +126,7 @@ func GetDefaults() Defaults {
DbDatabase: "postgres",
TemplateBaseDir: "./web/template/",
+ AssetBaseDir: "./web/assets/",
AccountsOpenRegistration: true,
AccountsRequireApproval: true,
diff --git a/internal/config/template.go b/internal/config/template.go
index eba86f8e6..9c524471c 100644
--- a/internal/config/template.go
+++ b/internal/config/template.go
@@ -22,4 +22,6 @@ package config
type TemplateConfig struct {
// Directory from which gotosocial will attempt to load html templates (.tmpl files).
BaseDir string `yaml:"baseDir"`
+ // Directory from which static files are served
+ AssetBaseDir string `yaml:"assetDir"`
}
diff --git a/internal/web/base.go b/internal/web/base.go
new file mode 100644
index 000000000..e54150ebc
--- /dev/null
+++ b/internal/web/base.go
@@ -0,0 +1,85 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+package web
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "path/filepath"
+
+ "github.com/gin-contrib/static"
+ "github.com/gin-gonic/gin"
+ "github.com/sirupsen/logrus"
+ "github.com/superseriousbusiness/gotosocial/internal/api"
+ "github.com/superseriousbusiness/gotosocial/internal/config"
+ "github.com/superseriousbusiness/gotosocial/internal/processing"
+ "github.com/superseriousbusiness/gotosocial/internal/router"
+)
+
+type Module struct {
+ config *config.Config
+ processor processing.Processor
+ log *logrus.Logger
+}
+
+func New(config *config.Config, processor processing.Processor, log *logrus.Logger) api.ClientModule {
+ return &Module{
+ config: config,
+ log: log,
+ processor: processor,
+ }
+}
+
+func (m *Module) baseHandler(c *gin.Context) {
+ l := m.log.WithField("func", "BaseGETHandler")
+ l.Trace("serving index html")
+
+ instance, err := m.processor.InstanceGet(m.config.Host)
+ if err != nil {
+ l.Debugf("error getting instance from processor: %s", err)
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"})
+ return
+ }
+
+ // FIXME: fill in more variables?
+ c.HTML(http.StatusOK, "index.tmpl", gin.H{
+ "instance": instance,
+ "countUsers": 3,
+ "countStatuses": 42069,
+ "version": "1.0.0",
+ "adminUsername": "@admin",
+ })
+}
+
+// Route satisfies the RESTAPIModule interface
+func (m *Module) Route(s router.Router) error {
+
+ // serve static files from /assets
+ cwd, err := os.Getwd()
+ if err != nil {
+ return fmt.Errorf("error getting current working directory: %s", err)
+ }
+ assetPath := filepath.Join(cwd, m.config.TemplateConfig.AssetBaseDir)
+ s.AttachMiddleware(static.Serve("/assets", static.LocalFile(assetPath, false)))
+
+ // serve front-page
+ s.AttachHandler(http.MethodGet, "/", m.baseHandler)
+ return nil
+}
diff --git a/web/assets/bundle.css b/web/assets/bundle.css
new file mode 100644
index 000000000..768510764
--- /dev/null
+++ b/web/assets/bundle.css
@@ -0,0 +1,191 @@
+html, body {
+ padding: 0;
+ margin: 0;
+ background: #525c66;
+ color: #fafaff;
+ font-family: sans-serif;
+}
+
+body {
+ display: grid;
+ grid-template-columns: 1fr 50% 1fr;
+ grid-template-columns: 1fr 90ch 1fr;
+ line-height: 1.5em;
+
+ min-height: 100vh;
+ grid-auto-rows: auto;
+ grid-auto-flow: dense;
+}
+
+body > * {
+ align-self: start;
+ grid-column: 2;
+ }
+
+body header, body footer, body .fullWidth {
+ grid-column: 1/4;
+ grid-column: 1/-1;
+ }
+
+body aside.left {
+ grid-column: 1;
+ }
+
+body aside.right {
+ grid-column: 3;
+ }
+
+header {
+ background: rgb(70, 79, 88);
+ padding: 2rem;
+ margin-bottom: 4rem;
+}
+
+h1 {
+ /* color: $acc1; */
+ margin: 0;
+ line-height: 2.4rem;
+}
+
+a {
+ color: #de8957;
+}
+
+a.button, button {
+ border-radius: 0.2rem;
+ background: #de8957;
+ color: #fafaff;
+ text-decoration: none;
+ font-size: 1.2rem;
+ font-weight: bold;
+ padding: 0.5rem;
+}
+
+a.button:hover, button:hover {
+ background: #c76d33;
+ }
+
+button {
+ border: none;
+ cursor: pointer;
+}
+
+.count {
+ background: rgb(70, 79, 88);
+ border-radius: 0.3rem;
+ padding: 0.2rem;
+}
+
+.nounderline {
+ text-decoration: none;
+}
+
+.accent {
+ color: #de8957;
+}
+
+aside.logo {
+ justify-self: center;
+}
+
+aside.logo img {
+ height: 30vh;
+ }
+
+section.apps {
+ align-self: start;
+}
+
+section.apps .applist {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-gap: 0.5rem;
+ align-content: start;
+ }
+
+section.apps .applist .entry {
+ display: grid;
+ grid-template-columns: 30% 1fr;
+ gap: 0.5rem;
+ padding: 0.5rem;
+ background: rgb(70, 79, 88);
+ border-radius: 0.5rem;
+ }
+
+section.apps .applist .entry .logo {
+ align-self: center;
+ width: 100%;
+ object-fit: contain;
+ flex: 1 1 auto;
+ }
+
+section.apps .applist .entry .logo.redraw {
+ fill: #fafaff;
+ stroke: #fafaff;
+ }
+
+section.apps .applist .entry div {
+ padding: 1rem 0;
+ }
+
+section.apps .applist .entry div h3 {
+ margin-top: 0;
+ }
+
+section.login form {
+ display: inline-grid;
+ grid-template-columns: auto 100%;
+ grid-gap: 0.7rem;
+ }
+
+section.login form input {
+ border: 1px solid #fafaff;
+ color: #fafaff;
+ background: #525c66;
+ width: 100%;
+ }
+
+section.login form button {
+ place-self: center;
+ grid-column: 2;
+ }
+
+footer {
+ align-self: end;
+
+ padding: 2rem;
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+}
+
+footer a {
+ font-weight: bold;
+ }
+
+@media screen and (orientation: portrait) {
+ body {
+ grid-template-columns: 1fr 92% 1fr;
+ }
+
+ body footer, body aside.left, body aside.right {
+ grid-column: 2;
+ }
+
+ header {
+ text-align: center;
+ }
+
+ footer {
+ padding: 0;
+ margin-top: 2rem;
+ grid-template-columns: 1fr;
+ }
+
+ footer div {
+ margin: 1rem 0;
+ }
+
+ section.apps .applist {
+ grid-template-columns: 1fr;
+ }
+}
\ No newline at end of file
diff --git a/assets/sloth.png b/web/assets/sloth.png
similarity index 100%
rename from assets/sloth.png
rename to web/assets/sloth.png
diff --git a/web/assets/tusky.svg b/web/assets/tusky.svg
new file mode 100644
index 000000000..1c48d6cdb
--- /dev/null
+++ b/web/assets/tusky.svg
@@ -0,0 +1,22 @@
+
\ No newline at end of file
diff --git a/web/source/build.js b/web/source/build.js
new file mode 100644
index 000000000..e32fa6da5
--- /dev/null
+++ b/web/source/build.js
@@ -0,0 +1,23 @@
+"use strict";
+
+const fs = require("fs").promises;
+const postcss = require('postcss');
+const {parse} = require("postcss-scss");
+
+const postcssPlugins = ["postcss-strip-inline-comments", "postcss-nested", "postcss-simple-vars", "postcss-color-function"].map((plugin) => require(plugin)());
+
+let inputFile = `${__dirname}/style.css`;
+let outputFile = `${__dirname}/../assets/bundle.css`;
+
+fs.readFile(inputFile, "utf-8").then((input) => {
+ return parse(input);
+}).then((ast) => {
+ return postcss(postcssPlugins).process(ast, {
+ from: "style.css",
+ to: "bundle.css"
+ });
+}).then((bundle) => {
+ return fs.writeFile(outputFile, bundle.css);
+}).then(() => {
+ console.log("Finished writing CSS bundle");
+});
diff --git a/web/source/package.json b/web/source/package.json
new file mode 100644
index 000000000..d58091118
--- /dev/null
+++ b/web/source/package.json
@@ -0,0 +1,11 @@
+{
+ "license": "AGPL-3.0",
+ "dependencies": {
+ "postcss": "^8.3.5",
+ "postcss-color-function": "^4.1.0",
+ "postcss-scss": "^4.0.0",
+ "postcss-nested": "^4.2.1",
+ "postcss-simple-vars": "^5.0.2",
+ "postcss-strip-inline-comments": "^0.1.5"
+ }
+}
diff --git a/web/source/style.css b/web/source/style.css
new file mode 100644
index 000000000..574293eda
--- /dev/null
+++ b/web/source/style.css
@@ -0,0 +1,199 @@
+$bg: #525c66;
+$fg: #fafaff;
+
+$bg_accent: color($bg lightness(-5%));
+
+$acc1: #de8957; // sloth light orange
+$acc2: #c76d33; // sloth dark orange
+
+html, body {
+ padding: 0;
+ margin: 0;
+ background: $bg;
+ color: $fg;
+ font-family: sans-serif;
+}
+
+body {
+ display: grid;
+ grid-template-columns: 1fr 50% 1fr;
+ grid-template-columns: 1fr 90ch 1fr;
+ line-height: 1.5em;
+
+ min-height: 100vh;
+ grid-auto-rows: auto;
+ grid-auto-flow: dense;
+
+ & > * {
+ align-self: start;
+ grid-column: 2;
+ }
+
+ header, footer, .fullWidth {
+ grid-column: 1/4;
+ grid-column: 1/-1;
+ }
+
+ aside.left {
+ grid-column: 1;
+ }
+
+ aside.right {
+ grid-column: 3;
+ }
+}
+
+header {
+ background: $bg_accent;
+ padding: 2rem;
+ margin-bottom: 4rem;
+}
+
+h1 {
+ /* color: $acc1; */
+ margin: 0;
+ line-height: 2.4rem;
+}
+
+a {
+ color: $acc1;
+}
+
+a.button, button {
+ border-radius: 0.2rem;
+ background: $acc1;
+ color: $fg;
+ text-decoration: none;
+ font-size: 1.2rem;
+ font-weight: bold;
+ padding: 0.5rem;
+
+ &:hover {
+ background: $acc2;
+ }
+}
+
+button {
+ border: none;
+ cursor: pointer;
+}
+
+.count {
+ background: $bg_accent;
+ border-radius: 0.3rem;
+ padding: 0.2rem;
+}
+
+.nounderline {
+ text-decoration: none;
+}
+
+.accent {
+ color: $acc1;
+}
+
+aside.logo {
+ justify-self: center;
+ img {
+ height: 30vh;
+ }
+}
+
+section.apps {
+ align-self: start;
+
+ .applist {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-gap: 0.5rem;
+ align-content: start;
+
+ .entry {
+ display: grid;
+ grid-template-columns: 30% 1fr;
+ gap: 0.5rem;
+ padding: 0.5rem;
+ background: $bg_accent;
+ border-radius: 0.5rem;
+
+ .logo {
+ align-self: center;
+ width: 100%;
+ object-fit: contain;
+ flex: 1 1 auto;
+ }
+
+ .logo.redraw {
+ fill: $fg;
+ stroke: $fg;
+ }
+
+ div {
+ padding: 1rem 0;
+ h3 {
+ margin-top: 0;
+ }
+ }
+ }
+ }
+}
+
+section.login {
+ form {
+ display: inline-grid;
+ grid-template-columns: auto 100%;
+ grid-gap: 0.7rem;
+
+ input {
+ border: 1px solid $fg;
+ color: $fg;
+ background: $bg;
+ width: 100%;
+ }
+
+ button {
+ place-self: center;
+ grid-column: 2;
+ }
+ }
+}
+
+footer {
+ align-self: end;
+
+ padding: 2rem;
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+
+ a {
+ font-weight: bold;
+ }
+}
+
+@media screen and (orientation: portrait) {
+ body {
+ grid-template-columns: 1fr 92% 1fr;
+
+ footer, aside.left, aside.right {
+ grid-column: 2;
+ }
+ }
+
+ header {
+ text-align: center;
+ }
+
+ footer {
+ padding: 0;
+ margin-top: 2rem;
+ grid-template-columns: 1fr;
+
+ div {
+ margin: 1rem 0;
+ }
+ }
+
+ section.apps .applist {
+ grid-template-columns: 1fr;
+ }
+}
\ No newline at end of file
diff --git a/web/source/yarn.lock b/web/source/yarn.lock
new file mode 100644
index 000000000..0ae871aa9
--- /dev/null
+++ b/web/source/yarn.lock
@@ -0,0 +1,297 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+ integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+balanced-match@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a"
+ integrity sha1-tQS9BYabOSWd0MXvw12EMXbczEo=
+
+chalk@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+chalk@^2.4.1, chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+clone@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+ integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
+
+color-convert@^1.3.0, color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+color-name@^1.0.0:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+color-string@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
+ integrity sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=
+ dependencies:
+ color-name "^1.0.0"
+
+color@^0.11.0:
+ version "0.11.4"
+ resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
+ integrity sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=
+ dependencies:
+ clone "^1.0.2"
+ color-convert "^1.3.0"
+ color-string "^0.3.0"
+
+colorette@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
+ integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
+
+css-color-function@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/css-color-function/-/css-color-function-1.3.3.tgz#8ed24c2c0205073339fafa004bc8c141fccb282e"
+ integrity sha1-jtJMLAIFBzM5+voAS8jBQfzLKC4=
+ dependencies:
+ balanced-match "0.1.0"
+ color "^0.11.0"
+ debug "^3.1.0"
+ rgb "~0.1.0"
+
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+debug@^3.1.0:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
+ dependencies:
+ ms "^2.1.1"
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+ integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+js-base64@^2.1.9:
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
+ integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
+
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+nanoid@^3.1.23:
+ version "3.1.23"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
+ integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
+
+postcss-color-function@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-color-function/-/postcss-color-function-4.1.0.tgz#b6f9355e07b12fcc5c34dab957834769b03d8f57"
+ integrity sha512-2/fuv6mP5Lt03XbRpVfMdGC8lRP1sykme+H1bR4ARyOmSMB8LPSjcL6EAI1iX6dqUF+jNEvKIVVXhan1w/oFDQ==
+ dependencies:
+ css-color-function "~1.3.3"
+ postcss "^6.0.23"
+ postcss-message-helpers "^2.0.0"
+ postcss-value-parser "^3.3.1"
+
+postcss-message-helpers@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e"
+ integrity sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=
+
+postcss-nested@^4.2.1:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-4.2.3.tgz#c6f255b0a720549776d220d00c4b70cd244136f6"
+ integrity sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw==
+ dependencies:
+ postcss "^7.0.32"
+ postcss-selector-parser "^6.0.2"
+
+postcss-scss@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.0.tgz#6cfe09040f01e3345c9c226894c5913ac5fa9381"
+ integrity sha512-xakgIr5ukOEyXFcsnADKjQtrk8nQyqn5VIEAA+PmPP4kBOpknmjpJMxBNqCR1/x20AS0aSfZkWsSdbMx2Ozm5A==
+
+postcss-selector-parser@^6.0.2:
+ version "6.0.6"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea"
+ integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-simple-vars@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-5.0.2.tgz#e2f81b3d0847ddd4169816b6d141b91d51e6e22e"
+ integrity sha512-xWIufxBoINJv6JiLb7jl5oElgp+6puJwvT5zZHliUSydoLz4DADRB3NDDsYgfKVwojn4TDLiseoC65MuS8oGGg==
+ dependencies:
+ postcss "^7.0.14"
+
+postcss-strip-inline-comments@^0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/postcss-strip-inline-comments/-/postcss-strip-inline-comments-0.1.5.tgz#7ff6bcdc14e633ed4cdfa020bae3eddad4f84b90"
+ integrity sha1-f/a83BTmM+1M36AguuPt2tT4S5A=
+ dependencies:
+ postcss "^5.0.18"
+
+postcss-value-parser@^3.3.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
+ integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
+
+postcss@^5.0.18:
+ version "5.2.18"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
+ integrity sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==
+ dependencies:
+ chalk "^1.1.3"
+ js-base64 "^2.1.9"
+ source-map "^0.5.6"
+ supports-color "^3.2.3"
+
+postcss@^6.0.23:
+ version "6.0.23"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
+ integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==
+ dependencies:
+ chalk "^2.4.1"
+ source-map "^0.6.1"
+ supports-color "^5.4.0"
+
+postcss@^7.0.14, postcss@^7.0.32:
+ version "7.0.36"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.36.tgz#056f8cffa939662a8f5905950c07d5285644dfcb"
+ integrity sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==
+ dependencies:
+ chalk "^2.4.2"
+ source-map "^0.6.1"
+ supports-color "^6.1.0"
+
+postcss@^8.3.5:
+ version "8.3.5"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709"
+ integrity sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==
+ dependencies:
+ colorette "^1.2.2"
+ nanoid "^3.1.23"
+ source-map-js "^0.6.2"
+
+rgb@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/rgb/-/rgb-0.1.0.tgz#be27b291e8feffeac1bd99729721bfa40fc037b5"
+ integrity sha1-vieykej+/+rBvZlylyG/pA/AN7U=
+
+source-map-js@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
+ integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
+
+source-map@^0.5.6:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+
+source-map@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+strip-ansi@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+ integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
+supports-color@^3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+ integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=
+ dependencies:
+ has-flag "^1.0.0"
+
+supports-color@^5.3.0, supports-color@^5.4.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
+ integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==
+ dependencies:
+ has-flag "^3.0.0"
+
+util-deprecate@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
diff --git a/web/template/authorize.tmpl b/web/template/authorize.tmpl
index fa6338b35..bc609ed66 100644
--- a/web/template/authorize.tmpl
+++ b/web/template/authorize.tmpl
@@ -1,34 +1,15 @@
-
-
-
-
- GoToSocial Authorization
-
-
-
-
-
-
-
-
-
+
+
+{{ template "footer.tmpl" .}}
\ No newline at end of file
diff --git a/web/template/footer.tmpl b/web/template/footer.tmpl
new file mode 100644
index 000000000..19e9cdbc4
--- /dev/null
+++ b/web/template/footer.tmpl
@@ -0,0 +1,13 @@
+
+
+