Added a site picker plus options to create new sites
This commit is contained in:
parent
cc0da8d668
commit
d80aacc180
|
|
@ -10,6 +10,15 @@ $container-max-widths: (
|
||||||
|
|
||||||
@import "bootstrap/scss/bootstrap.scss";
|
@import "bootstrap/scss/bootstrap.scss";
|
||||||
|
|
||||||
|
// Navbar
|
||||||
|
|
||||||
|
.navbar-site-visit {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 2em;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
// Post list
|
// Post list
|
||||||
|
|
||||||
.postlist .post img {
|
.postlist .post img {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import feather from "feather-icons/dist/feather.js";
|
||||||
import { Application } from "@hotwired/stimulus";
|
import { Application } from "@hotwired/stimulus";
|
||||||
|
|
||||||
import ToastController from "./controllers/toast";
|
import ToastController from "./controllers/toast";
|
||||||
|
|
@ -17,4 +18,6 @@ Stimulus.register("logout", LogoutController);
|
||||||
Stimulus.register("first-run", FirstRunController);
|
Stimulus.register("first-run", FirstRunController);
|
||||||
Stimulus.register("upload", UploadController);
|
Stimulus.register("upload", UploadController);
|
||||||
Stimulus.register("show-upload", ShowUploadController);
|
Stimulus.register("show-upload", ShowUploadController);
|
||||||
Stimulus.register("pagelist", PagelistController);
|
Stimulus.register("pagelist", PagelistController);
|
||||||
|
|
||||||
|
feather.replace();
|
||||||
|
|
@ -119,7 +119,17 @@ Starting weiro without any arguments will start the server.
|
||||||
app.Post("/login", lh.DoLogin)
|
app.Post("/login", lh.DoLogin)
|
||||||
app.Post("/logout", lh.Logout)
|
app.Post("/logout", lh.Logout)
|
||||||
|
|
||||||
siteGroup := app.Group("/sites/:siteID", middleware.LogErrors(), middleware.RequireUser(svcs.Auth), middleware.RequiresSite(svcs.Sites))
|
app.Get("/", middleware.OptionalUser(svcs.Auth), ih.Index)
|
||||||
|
app.Get("/first-run", ih.FirstRun)
|
||||||
|
app.Post("/first-run", ih.FirstRunSubmit)
|
||||||
|
|
||||||
|
app.Get("/static/*", static.New("./static"))
|
||||||
|
|
||||||
|
app.Use(middleware.LogErrors(), middleware.RequireUser(svcs.Auth))
|
||||||
|
|
||||||
|
app.Get("/sites/new", ssh.New)
|
||||||
|
app.Post("/sites", ssh.Create)
|
||||||
|
siteGroup := app.Group("/sites/:siteID", middleware.RequiresSite(svcs.Sites))
|
||||||
|
|
||||||
siteGroup.Get("/posts", ph.Index)
|
siteGroup.Get("/posts", ph.Index)
|
||||||
siteGroup.Get("/posts/new", ph.New)
|
siteGroup.Get("/posts/new", ph.New)
|
||||||
|
|
@ -158,12 +168,6 @@ Starting weiro without any arguments will start the server.
|
||||||
siteGroup.Post("/pages/:pageID", pgh.Update)
|
siteGroup.Post("/pages/:pageID", pgh.Update)
|
||||||
siteGroup.Post("/pages/:pageID/delete", pgh.Delete)
|
siteGroup.Post("/pages/:pageID/delete", pgh.Delete)
|
||||||
|
|
||||||
app.Get("/", middleware.OptionalUser(svcs.Auth), ih.Index)
|
|
||||||
app.Get("/first-run", ih.FirstRun)
|
|
||||||
app.Post("/first-run", ih.FirstRunSubmit)
|
|
||||||
|
|
||||||
app.Get("/static/*", static.New("./static"))
|
|
||||||
|
|
||||||
if err := app.Listen(":3000"); err != nil {
|
if err := app.Listen(":3000"); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
func LogErrors() func(c fiber.Ctx) error {
|
func LogErrors() func(c fiber.Ctx) error {
|
||||||
return func(c fiber.Ctx) error {
|
return func(c fiber.Ctx) error {
|
||||||
if err := c.Next(); err != nil {
|
if err := c.Next(); err != nil {
|
||||||
log.Printf("error: %v\n", err)
|
log.Printf("%v: error: %v\n", c.Path(), err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,19 @@ func RequiresSite(sites *sites.Service) func(c fiber.Ctx) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Locals("site", site)
|
c.Locals("site", site)
|
||||||
c.SetContext(models.WithSite(c.Context(), site))
|
c.SetContext(models.WithSite(c.Context(), site))
|
||||||
|
|
||||||
|
sitesOwnedByUser, err := sites.ListSites(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Locals("allSites", sitesOwnedByUser)
|
||||||
|
|
||||||
|
if pubTargets, err := sites.BestPubTarget(c.Context(), site); err == nil {
|
||||||
|
c.Locals("pubTarget", pubTargets)
|
||||||
|
}
|
||||||
|
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,28 @@ type SiteSettingsHandler struct {
|
||||||
SiteService *sites.Service
|
SiteService *sites.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SiteSettingsHandler) General(ctx fiber.Ctx) error {
|
func (s *SiteSettingsHandler) New(c fiber.Ctx) error {
|
||||||
site := ctx.Locals("site").(models.Site)
|
return c.Render("sitesettings/new", fiber.Map{}, "layouts/bare_with_scripts")
|
||||||
|
}
|
||||||
|
|
||||||
return ctx.Render("sitesettings/general", fiber.Map{
|
func (s *SiteSettingsHandler) Create(c fiber.Ctx) error {
|
||||||
|
var params sites.CreateSiteParams
|
||||||
|
if err := c.Bind().Body(¶ms); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newSite, err := s.SiteService.CreateSite(c.Context(), params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect().To(fmt.Sprintf("/sites/%v/posts", newSite.ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SiteSettingsHandler) General(c fiber.Ctx) error {
|
||||||
|
site := c.Locals("site").(models.Site)
|
||||||
|
|
||||||
|
return c.Render("sitesettings/general", fiber.Map{
|
||||||
"site": site,
|
"site": site,
|
||||||
"tzones": sites.ListZones(),
|
"tzones": sites.ListZones(),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
36
package-lock.json
generated
36
package-lock.json
generated
|
|
@ -7,7 +7,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hotwired/stimulus": "^3.2.2",
|
"@hotwired/stimulus": "^3.2.2",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
"esbuild-sass-plugin": "^3.6.0"
|
"esbuild-sass-plugin": "^3.6.0",
|
||||||
|
"feather-icons": "^4.29.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "0.27.3"
|
"esbuild": "0.27.3"
|
||||||
|
|
@ -783,6 +784,12 @@
|
||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/colorjs.io": {
|
"node_modules/colorjs.io": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
|
||||||
|
|
@ -790,6 +797,17 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/core-js": {
|
||||||
|
"version": "3.49.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz",
|
||||||
|
"integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/core-js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/detect-libc": {
|
"node_modules/detect-libc": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||||
|
|
@ -855,6 +873,16 @@
|
||||||
"sass-embedded": "^1.97.2"
|
"sass-embedded": "^1.97.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/feather-icons": {
|
||||||
|
"version": "4.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/feather-icons/-/feather-icons-4.29.2.tgz",
|
||||||
|
"integrity": "sha512-0TaCFTnBTVCz6U+baY2UJNKne5ifGh7sMG4ZC2LoBWCZdIyPa+y6UiR4lEYGws1JOFWdee8KAsAIvu0VcXqiqA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"core-js": "^3.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
|
|
@ -887,9 +915,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/immutable": {
|
"node_modules/immutable": {
|
||||||
"version": "5.1.4",
|
"version": "5.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
|
||||||
"integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
|
"integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hotwired/stimulus": "^3.2.2",
|
"@hotwired/stimulus": "^3.2.2",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
"esbuild-sass-plugin": "^3.6.0"
|
"esbuild-sass-plugin": "^3.6.0",
|
||||||
|
"feather-icons": "^4.29.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
"lmika.dev/lmika/weiro/models"
|
"lmika.dev/lmika/weiro/models"
|
||||||
"lmika.dev/lmika/weiro/providers/db"
|
"lmika.dev/lmika/weiro/providers/db"
|
||||||
|
"lmika.dev/pkg/modash/moslice"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
|
@ -25,6 +26,22 @@ func (s *Service) HasUsersAsSites(ctx context.Context) (bool, error) {
|
||||||
return s.db.HasUsersAndSites(ctx)
|
return s.db.HasUsersAndSites(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListSites(ctx context.Context) ([]models.Site, error) {
|
||||||
|
user, ok := models.GetUser(ctx)
|
||||||
|
if !ok {
|
||||||
|
return nil, models.UserRequiredError
|
||||||
|
}
|
||||||
|
|
||||||
|
sites, err := s.db.SelectSitesOwnedByUser(ctx, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(sites) == 0 {
|
||||||
|
return nil, errors.New("no sites found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return sites, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) BestSite(ctx context.Context, user models.User) (models.Site, error) {
|
func (s *Service) BestSite(ctx context.Context, user models.User) (models.Site, error) {
|
||||||
sites, err := s.db.SelectSitesOwnedByUser(ctx, user.ID)
|
sites, err := s.db.SelectSitesOwnedByUser(ctx, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -36,16 +53,20 @@ func (s *Service) BestSite(ctx context.Context, user models.User) (models.Site,
|
||||||
return sites[0], nil
|
return sites[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type FirstRunRequest struct {
|
type CreateSiteParams struct {
|
||||||
Username string `form:"username"`
|
|
||||||
Password1 string `form:"password1"`
|
|
||||||
Password2 string `form:"password2"`
|
|
||||||
SiteName string `form:"siteName"`
|
SiteName string `form:"siteName"`
|
||||||
SiteURL string `form:"siteUrl"`
|
SiteURL string `form:"siteUrl"`
|
||||||
NetlifySiteID string `form:"netlifySiteId"`
|
NetlifySiteID string `form:"netlifySiteId"`
|
||||||
NetlifyAPIKey string `form:"netlifyAPIToken"`
|
NetlifyAPIKey string `form:"netlifyAPIToken"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FirstRunRequest struct {
|
||||||
|
CreateSiteParams
|
||||||
|
Username string `form:"username"`
|
||||||
|
Password1 string `form:"password1"`
|
||||||
|
Password2 string `form:"password2"`
|
||||||
|
}
|
||||||
|
|
||||||
func (frr FirstRunRequest) Validate() error {
|
func (frr FirstRunRequest) Validate() error {
|
||||||
return validation.ValidateStruct(&frr,
|
return validation.ValidateStruct(&frr,
|
||||||
validation.Field(&frr.Username, validation.Required, validation.Match(models.ValidUserName)),
|
validation.Field(&frr.Username, validation.Required, validation.Match(models.ValidUserName)),
|
||||||
|
|
@ -76,16 +97,31 @@ func (s *Service) FirstRun(ctx context.Context, req FirstRunRequest) (newUser mo
|
||||||
return newUser, newSite, err
|
return newUser, newSite, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx = models.WithUser(ctx, newUser)
|
||||||
|
newSite, err = s.CreateSite(ctx, req.CreateSiteParams)
|
||||||
|
if err != nil {
|
||||||
|
return newUser, newSite, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newUser, newSite, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateSite(ctx context.Context, req CreateSiteParams) (newSite models.Site, _ error) {
|
||||||
|
user, ok := models.GetUser(ctx)
|
||||||
|
if !ok {
|
||||||
|
return newSite, models.UserRequiredError
|
||||||
|
}
|
||||||
|
|
||||||
newSite = models.Site{
|
newSite = models.Site{
|
||||||
Title: defaultIfEmpty(req.SiteName, "New Site"),
|
Title: defaultIfEmpty(req.SiteName, "New Site"),
|
||||||
GUID: models.NewNanoID(),
|
GUID: models.NewNanoID(),
|
||||||
OwnerID: newUser.ID,
|
OwnerID: user.ID,
|
||||||
Timezone: "UTC",
|
Timezone: "UTC",
|
||||||
PostsPerPage: 10,
|
PostsPerPage: 10,
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
}
|
}
|
||||||
if err := s.db.SaveSite(ctx, &newSite); err != nil {
|
if err := s.db.SaveSite(ctx, &newSite); err != nil {
|
||||||
return newUser, newSite, err
|
return newSite, err
|
||||||
}
|
}
|
||||||
|
|
||||||
hasNetlifyConfig := req.SiteURL != "" && req.NetlifySiteID != "" && req.NetlifyAPIKey != ""
|
hasNetlifyConfig := req.SiteURL != "" && req.NetlifySiteID != "" && req.NetlifyAPIKey != ""
|
||||||
|
|
@ -100,11 +136,11 @@ func (s *Service) FirstRun(ctx context.Context, req FirstRunRequest) (newUser mo
|
||||||
TargetKey: req.NetlifyAPIKey,
|
TargetKey: req.NetlifyAPIKey,
|
||||||
}
|
}
|
||||||
if err := s.db.SavePublishTarget(ctx, &target); err != nil {
|
if err := s.db.SavePublishTarget(ctx, &target); err != nil {
|
||||||
return newUser, newSite, err
|
return newSite, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newUser, newSite, nil
|
return newSite, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetSiteByID(ctx context.Context, siteID int64) (models.Site, error) {
|
func (s *Service) GetSiteByID(ctx context.Context, siteID int64) (models.Site, error) {
|
||||||
|
|
@ -166,3 +202,17 @@ func (s *Service) UpdateSiteSettings(ctx context.Context, params UpdateSiteSetti
|
||||||
|
|
||||||
return site, nil
|
return site, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) BestPubTarget(ctx context.Context, site models.Site) (models.SitePublishTarget, error) {
|
||||||
|
pubTargets, err := s.db.SelectPublishTargetsOfSite(ctx, site.ID)
|
||||||
|
if err != nil {
|
||||||
|
return models.SitePublishTarget{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
enabledPubTargets := moslice.Filter(pubTargets, func(pubTarget models.SitePublishTarget) bool { return pubTarget.Enabled })
|
||||||
|
if len(enabledPubTargets) == 0 {
|
||||||
|
return models.SitePublishTarget{}, errors.New("no publish targets found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return enabledPubTargets[0], nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,25 @@
|
||||||
<span class="visually-hidden">Publishing...</span>
|
<span class="visually-hidden">Publishing...</span>
|
||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
|
<div class="nav-item dropdown me-2">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{{ .site.Title }}
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
{{ range .allSites }}
|
||||||
|
<li><a class="dropdown-item" href="/sites/{{.ID}}/posts">{{.Title}}</a></li>
|
||||||
|
{{ end }}
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="/sites/new">New Site…</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item dropdown border-end me-3">
|
||||||
|
{{ if .pubTarget }}
|
||||||
|
<a href="{{.pubTarget.BaseURL}}" class="nav-link navbar-site-visit" target="_blank" title="Visit site">
|
||||||
|
<i data-feather="external-link" width="18" height="18"></i>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
<div class="nav-item dropdown">
|
<div class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
{{ .user.Username }}
|
{{ .user.Username }}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div data-first-run-target="pages">
|
<div data-first-run-target="pages">
|
||||||
<div class="text-center mb-4">
|
<div class="text-center mb-4">
|
||||||
<p>Enter the details of your blog, if you know them.<br>All fields are optional, and can be changed later.</p>
|
<p>Enter the details of your blog if you know them.<br>All fields are optional and can be changed later.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<label for="siteName" class="form-label">Site Name</label>
|
<label for="siteName" class="form-label">Site Name</label>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
</table>
|
</table>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<div class="h4 m-3 text-center">
|
<div class="h4 m-3 text-center">
|
||||||
<div class="position-absolute top-50 start-50 translate-middle">No pages yet.</div>
|
<div class="position-absolute top-50 start-50 translate-middle">📄<br>No pages yet.</div>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
29
views/sitesettings/new.html
Normal file
29
views/sitesettings/new.html
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<div class="mx-auto p-2" style="width: 400px; margin-block-start: 50px;" data-controller="first-run">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1>New Site</h1>
|
||||||
|
</div>
|
||||||
|
<form action="/sites" method="post">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<p>Enter the details of your blog if you know them.<br>All fields are optional and can be changed later.</p>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="siteName" class="form-label">Site Name</label>
|
||||||
|
<input type="text" class="form-control" name="siteName" id="siteName">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="siteUrl" class="form-label">Site URL</label>
|
||||||
|
<input type="text" class="form-control" name="siteUrl" id="siteUrl">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="netlifySiteId" class="form-label">Netlify Site ID</label>
|
||||||
|
<input type="text" class="form-control" name="netlifySiteId" id="netlifySiteId">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="netlifyAPIToken" class="form-label">Netlify API Token</label>
|
||||||
|
<input type="text" class="form-control" name="netlifyAPIToken" id="netlifyAPIToken">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 text-end">
|
||||||
|
<input type="submit" class="btn btn-primary" value="Create Site">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
@ -20,5 +20,9 @@
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
{{ else }}
|
||||||
|
<div class="h4 m-3 text-center">
|
||||||
|
<div class="position-absolute top-50 start-50 translate-middle">🖼️<br>No uploads yet.</div>
|
||||||
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</main>
|
</main>
|
||||||
Loading…
Reference in a new issue