~evanj/cms

8edd2c746f62d805e3176aebb05c281788e6c7c6 — Evan M Jones 1 year, 8 months ago ab7c5d1
Feat(css): Adding "mvp" css.
M internal/s/db/contenttype.go => internal/s/db/contenttype.go +14 -14
@@ 9,9 9,9 @@ import (
)

type ContentType struct {
	ParentID     string
	ParentName   string
	ParentFields []ContentTypeField
	ContentTypeID     string
	ContentTypeName   string
	ContentTypeFields []ContentTypeField
}

type ContentTypeField struct {


@@ 74,12 74,12 @@ func (db *DB) ContentTypeNew(space space.Space, name string, params []ContentTyp
	// }

	var ct ContentType
	if err := db.QueryRow(queryFindContentTypeByID, id).Scan(&ct.ParentID, &ct.ParentName); err != nil {
	if err := db.QueryRow(queryFindContentTypeByID, id).Scan(&ct.ContentTypeID, &ct.ContentTypeName); err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to find user created")
	}

	rows, err := db.Query(queryFindValueTypes, ct.ParentID)
	rows, err := db.Query(queryFindValueTypes, ct.ContentTypeID)
	if err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to find field(s)")


@@ 89,10 89,10 @@ func (db *DB) ContentTypeNew(space space.Space, name string, params []ContentTyp
		if err := rows.Scan(&field.FieldID, &field.FieldName, &field.FieldType); err != nil {
			return nil, fmt.Errorf("failed to scan field(s)")
		}
		ct.ParentFields = append(ct.ParentFields, field)
		ct.ContentTypeFields = append(ct.ContentTypeFields, field)
	}

	if len(ct.ParentFields) != len(params) {
	if len(ct.ContentTypeFields) != len(params) {
		return nil, fmt.Errorf("failed to create all fields")
	}



@@ 109,7 109,7 @@ func (db *DB) ContentTypesPerSpace(space space.Space, page int) ([]contenttype.C

	for rows.Next() {
		var ct ContentType
		if err := rows.Scan(&ct.ParentID, &ct.ParentName); err != nil {
		if err := rows.Scan(&ct.ContentTypeID, &ct.ContentTypeName); err != nil {
			return nil, err
		}
		ret = append(ret, &ct)


@@ 120,12 120,12 @@ func (db *DB) ContentTypesPerSpace(space space.Space, page int) ([]contenttype.C

func (db *DB) ContentTypeGet(space space.Space, contenttypeID string) (contenttype.ContentType, error) {
	var ct ContentType
	if err := db.QueryRow(queryFindContentTypeByIDAndSpace, contenttypeID, space.ID()).Scan(&ct.ParentID, &ct.ParentName); err != nil {
	if err := db.QueryRow(queryFindContentTypeByIDAndSpace, contenttypeID, space.ID()).Scan(&ct.ContentTypeID, &ct.ContentTypeName); err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to find contenttype for space")
	}

	rows, err := db.Query(queryFindValueTypes, ct.ParentID)
	rows, err := db.Query(queryFindValueTypes, ct.ContentTypeID)
	if err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to find field(s)")


@@ 135,23 135,23 @@ func (db *DB) ContentTypeGet(space space.Space, contenttypeID string) (contentty
		if err := rows.Scan(&field.FieldID, &field.FieldName, &field.FieldType); err != nil {
			return nil, fmt.Errorf("failed to scan field(s)")
		}
		ct.ParentFields = append(ct.ParentFields, field)
		ct.ContentTypeFields = append(ct.ContentTypeFields, field)
	}

	return &ct, nil
}

func (ct *ContentType) ID() string {
	return ct.ParentID
	return ct.ContentTypeID
}

func (ct *ContentType) Name() string {
	return ct.ParentName
	return ct.ContentTypeName
}

func (ct *ContentType) Fields() []valuetype.ValueType {
	var ret []valuetype.ValueType
	for _, item := range ct.ParentFields {
	for _, item := range ct.ContentTypeFields {
		ret = append(ret, &ContentTypeField{
			item.FieldID,
			item.FieldName,

M internal/s/db/space.go => internal/s/db/space.go +9 -18
@@ 1,7 1,6 @@
package db

import (
	"encoding/json"
	"fmt"

	"git.sr.ht/~evanj/cms/internal/m/space"


@@ 9,9 8,9 @@ import (
)

type Space struct {
	id   string
	name string
	desc string
	SpaceID   string
	SpaceName string
	SpaceDesc string
}

var (


@@ 37,7 36,7 @@ func (db *DB) SpaceNew(user user.User, name, desc string) (space.Space, error) {
	}

	var space Space
	if err := db.QueryRow(queryFindSpaceByID, id).Scan(&space.id, &space.name, &space.desc); err != nil {
	if err := db.QueryRow(queryFindSpaceByID, id).Scan(&space.SpaceID, &space.SpaceName, &space.SpaceDesc); err != nil {
		db.log.Println("db.QueryRow", err)
		return nil, fmt.Errorf("failed to find space created")
	}


@@ 62,7 61,7 @@ func (db *DB) SpaceGet(user user.User, spaceID string) (space.Space, error) {
	}

	var space Space
	err := db.QueryRow(queryFindSpaceByID, id).Scan(&space.id, &space.name, &space.desc)
	err := db.QueryRow(queryFindSpaceByID, id).Scan(&space.SpaceID, &space.SpaceName, &space.SpaceDesc)
	if err != nil {
		db.log.Println("db.Exec", err)
		return nil, fmt.Errorf("failed to find space")


@@ 81,7 80,7 @@ func (db *DB) SpacesPerUser(user user.User, page int) ([]space.Space, error) {

	for rows.Next() {
		var space Space
		if err := rows.Scan(&space.id, &space.name, &space.desc); err != nil {
		if err := rows.Scan(&space.SpaceID, &space.SpaceName, &space.SpaceDesc); err != nil {
			return nil, err
		}
		ret = append(ret, &space)


@@ 91,21 90,13 @@ func (db *DB) SpacesPerUser(user user.User, page int) ([]space.Space, error) {
}

func (s *Space) ID() string {
	return s.id
	return s.SpaceID
}

func (s *Space) Name() string {
	return s.name
	return s.SpaceName
}

func (s *Space) Desc() string {
	return s.desc
}

func (c *Space) MarshalJSON() ([]byte, error) {
	values := make(map[string]string)
	values["id"] = c.ID()
	values["name"] = c.Name()
	values["desc"] = c.Desc()
	return json.Marshal(values)
	return s.SpaceDesc
}

M internal/s/db/user.go => internal/s/db/user.go +19 -26
@@ 1,7 1,6 @@
package db

import (
	"encoding/json"
	"fmt"

	"git.sr.ht/~evanj/cms/internal/m/user"


@@ 9,11 8,12 @@ import (
)

type User struct {
	id   string
	name string
	hash string

	token string
	// Stored in DB.
	UserID   string
	UserName string
	userHash string
	// Set on read.
	userToken string
}

// SQL QUERIES


@@ 48,39 48,39 @@ func (db *DB) UserNew(username, password, verifyPassword string) (user.User, err
	}

	var user User
	if err := db.QueryRow(queryFindUserByID, id).Scan(&user.id, &user.name, &user.hash); err != nil {
	if err := db.QueryRow(queryFindUserByID, id).Scan(&user.UserID, &user.UserName, &user.userHash); err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to find user created")
	}

	tok, err := db.sec.TokenCreate(security.TokenMap{"ID": user.id})
	tok, err := db.sec.TokenCreate(security.TokenMap{"ID": user.UserID})
	if err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to create token for user")
	}

	user.token = tok
	user.userToken = tok
	return &user, nil
}

func (db *DB) UserGet(username, password string) (user.User, error) {
	var user User
	if err := db.QueryRow(queryFindUserByName, username).Scan(&user.id, &user.name, &user.hash); err != nil {
	if err := db.QueryRow(queryFindUserByName, username).Scan(&user.UserID, &user.UserName, &user.userHash); err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to find user '%s'", username)
	}

	if err := db.sec.HashCompare(username, password, user.hash); err != nil {
	if err := db.sec.HashCompare(username, password, user.userHash); err != nil {
		return nil, fmt.Errorf("incorrect password")
	}

	tok, err := db.sec.TokenCreate(security.TokenMap{"ID": user.id})
	tok, err := db.sec.TokenCreate(security.TokenMap{"ID": user.UserID})
	if err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to create token for user")
	}

	user.token = tok
	user.userToken = tok
	return &user, nil
}



@@ 98,36 98,29 @@ func (db *DB) UserGetFromToken(token string) (user.User, error) {
	}

	var user User
	if err := db.QueryRow(queryFindUserByID, id).Scan(&user.id, &user.name, &user.hash); err != nil {
	if err := db.QueryRow(queryFindUserByID, id).Scan(&user.UserID, &user.UserName, &user.userHash); err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to find user")
	}

	tok, err := db.sec.TokenCreate(security.TokenMap{"ID": user.id})
	tok, err := db.sec.TokenCreate(security.TokenMap{"ID": user.UserID})
	if err != nil {
		db.log.Println(err)
		return nil, fmt.Errorf("failed to create token for user")
	}

	user.token = tok
	user.userToken = tok
	return &user, nil
}

func (u *User) ID() string {
	return u.id
	return u.UserID
}

func (u *User) Name() string {
	return u.name
	return u.UserName
}

func (u *User) Token() string {
	return u.token
}

func (u *User) MarshalJSON() ([]byte, error) {
	values := make(map[string]string)
	values["id"] = u.ID()
	values["name"] = u.Name()
	return json.Marshal(values)
	return u.userToken
}

M internal/s/tmpl/css/main.css => internal/s/tmpl/css/main.css +18 -6
@@ 1,9 1,3 @@
* { 
  padding: 0;
  margin: 0;
  list-style: none;
}

body {
}



@@ 26,6 20,8 @@ button {

textarea { 
  width: 100%%;
  resize: vertical;
  min-height: 250px;
}

.input-html,


@@ 33,9 29,25 @@ textarea {
  display: block !important; /* tinymce hides this. */
  width: 0;
  height: 0;
  min-height: 0;
  resize: none;
  overflow: hidden;
  position: relative;
  left: 50%%;
  top: 100px;
  margin: 0;
  padding: 0;
}

/* To match stylesheet. */

form > legend,
.tox.tox-tinymce { 
  margin-bottom: 16px;
}

details > form {
  margin-top: 16px;
  margin-bottom: 16px;
}


M internal/s/tmpl/html/_head.html => internal/s/tmpl/html/_head.html +2 -1
@@ 1,3 1,4 @@
<meta charset="utf-8">
<link rel="icon" type="image/x-icon" href="https://favicon.evanjon.es/255/0/0/32/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="https://favicon.evanjon.es/255/0/0/32/favicon.ico" />
<link rel="stylesheet" href="https://andybrewer.github.io/mvp/mvp.css">

M internal/s/tmpl/html/content.html => internal/s/tmpl/html/content.html +3 -9
@@ 14,13 14,7 @@
    <hr/>
    <article>

      <nav>
        <a href='/contenttype/{{ .Space.ID }}/{{ .ContentType.ID }}'>Back</a>
      </nav>

      <h1>Space: {{ .Space.Name }}</h1>
      <h2>Content Type: {{ .ContentType.Name }}</h2>
      <h3>Content: {{ (.Content.MustValueByName "name").Value }}</h3>
      <h1>{{ .Space.Name }} > {{ .ContentType.Name }} > {{ (.Content.MustValueByName "name").Value }}</h1>

      <details>
        <summary>Update Content</summary>


@@ 59,7 53,7 @@

          {{ end }}

          <input type=submit value=Go />
          <input type=submit value=Update />
        </form>
      </details>



@@ 69,7 63,7 @@
          <input required type=hidden name=space value="{{ .Space.ID }}" />
          <input required type=hidden name=contenttype value="{{ .ContentType.ID }}" />
          <input required type=hidden name=content value="{{ .Content.ID }}" />
          <input type=submit value=Go />
          <input type=submit value=Delete />
        </form>
      </details>


M internal/s/tmpl/html/contenttype.html => internal/s/tmpl/html/contenttype.html +17 -24
@@ 3,7 3,7 @@

<head>
  {{ template "html/_head.html" }}
  <title>CMS | {{ .Space.Name }} | {{ .ContenType.Name }}</title>
  <title>CMS | {{ .Space.Name }} | {{ .ContentType.Name }}</title>
</head>

<body>


@@ 14,12 14,7 @@
    <hr/>
    <article>

      <nav>
        <a href='/space/{{ .Space.ID }}'>Back</a>
      </nav>

      <h1>Space: {{ .Space.Name }}</h1>
      <h2>Content Type: {{ .ContentType.Name }}</h2>
      <h1>{{ .Space.Name }} > {{ .ContentType.Name }}</h1>

      <details>
        <summary>Create a {{ .ContentType.Name }} Content</summary>


@@ 58,26 53,24 @@

          {{ end }}

          <input type=submit value=Go />
          <input type=submit value=Create />
        </form>
      </details>

      <details>
        <summary>Browse {{ .ContentType.Name }} Content</summary>
        {{ if .ContentList }}
          <ul>
            {{ range .ContentList }}
              <li> 
                <a href='/content/{{ $.Space.ID }}/{{ $.ContentType.ID }}/{{ .ID }}'>
                  {{ (.MustValueByName "name").Value }}
                </a>
              </li>
            {{ end }}
          </ul>
        {{ else }}
          <p>No content has been created with a content type of {{ .ContentType.Name }}</p>
        {{ end }}
      </details>
      <h2>Browse {{ .ContentType.Name }} Content</h2>
      {{ if .ContentList }}
        <ul>
          {{ range .ContentList }}
            <li> 
              <a href='/content/{{ $.Space.ID }}/{{ $.ContentType.ID }}/{{ .ID }}'>
                {{ (.MustValueByName "name").Value }}
              </a>
            </li>
          {{ end }}
        </ul>
      {{ else }}
        <p>No content has been created with a content type of {{ .ContentType.Name }}</p>
      {{ end }}

    </article>
    <hr/>

M internal/s/tmpl/html/index.html => internal/s/tmpl/html/index.html +18 -17
@@ 14,6 14,7 @@
    <hr/>
    <article>

      <h1>Home</h1>

      {{ if .User }}



@@ 22,30 23,30 @@
          <form method=POST action='/space/new' enctype='multipart/form-data'>
            <input required type=text name=name placeholder=name />
            <input required type=text name=desc placeholder=description />
            <input type=submit value=Go />
            <input type=submit value=Create />
          </form>
        </details>

        <details>
          <summary>Available Spaces</summary>
          {{ if .Spaces }}
            <ul>
              {{ range .Spaces }}
              <li><a href="/space/{{ .ID }}">{{ .Name }}</a></li>
              {{ end }}
            </ul>
          {{ else }}
            <p>You haven't created any spaces yet.</p>
          {{ end }}
        </details>

        <details>
          <summary>Logout</summary>
          <form method=POST action='/user/logout' enctype='multipart/form-data'>
            <input type=submit value=Go />
            <input type=submit value=Logout />
          </form>
        </details>

        <br/>

        <h2>Available Spaces</h2>
        {{ if .Spaces }}
          <ul>
            {{ range .Spaces }}
            <li><a href="/space/{{ .ID }}">{{ .Name }}</a></li>
            {{ end }}
          </ul>
        {{ else }}
          <p>You haven't created any spaces yet.</p>
        {{ end }}

      {{ else }}

        <details>


@@ 53,7 54,7 @@
          <form method=POST action='/user/login' enctype='multipart/form-data'>
            <input autocomplete=on required type=text name=username placeholder=username autofocus />
            <input autocomplete=on required type=password name=password placeholder=password />
            <input type=submit value=Go />
            <input type=submit value=Login />
          </form>
        </details>



@@ 63,7 64,7 @@
            <input autocomplete=on required type=text name=username placeholder=username autofocus />
            <input autocomplete=on required type=password name=password placeholder=password />
            <input autocomplete=on required type=password name=verify placeholder=verify />
            <input type=submit value=Go />
            <input type=submit value=Signup />
          </form>
        </details>


M internal/s/tmpl/html/space.html => internal/s/tmpl/html/space.html +13 -18
@@ 14,17 14,14 @@
    <hr/>
    <article>

      <nav>
        <a href='/'>Back</a>
      </nav>

      <h1>Space: {{ .Space.Name }}</h1>
      <h1>{{ .Space.Name }}</h1>

      <details>
        <summary>Create Content Type</summary>
        <form method=POST action='/contenttype/new' enctype='multipart/form-data'>
          <input required type=hidden name=space value="{{ .Space.ID }}" />
          <input required type=text name=name placeholder="content type name" />
          <legend>Fields</legend>
          <div id='first-fieldset'>
            <input readonly="readonly" required type=text name="field_name_1" value="name" />
            <select readonly="readonly" required name="field_type_1">


@@ 38,22 35,20 @@
            </select>
          </div>
          <button id='add-fieldbtn'>Add Another Field</button>
          <input type=submit value=Go />
          <input type=submit value=Create />
        </form>
      </details>

      <details>
        <summary>Browse Content By Type</summary>
        {{ if .ContentTypes }}
          <ul>
            {{ range .ContentTypes }}
              <li><a href='/contenttype/{{ $.Space.ID }}/{{ .ID }}'>{{ .Name }}</a></li>
            {{ end }}
          </ul>
        {{ else }}
          <p>You haven't created any content types yet.</p>
        {{ end }}
      </details>
      <h2>Browse Content By Type</h2>
      {{ if .ContentTypes }}
        <ul>
          {{ range .ContentTypes }}
            <li><a href='/contenttype/{{ $.Space.ID }}/{{ .ID }}'>{{ .Name }}</a></li>
          {{ end }}
        </ul>
      {{ else }}
        <p>You haven't created any content types yet.</p>
      {{ end }}

    </article>
    <hr/>

M internal/s/tmpl/tmpls_embed.go => internal/s/tmpl/tmpls_embed.go +72 -76
@@ 7,13 7,7 @@ var tmpls map[string]string
func init() {
	tmpls = make(map[string]string)

	tmpls["css/main.css"] = `* { 
  padding: 0;
  margin: 0;
  list-style: none;
}

body {
	tmpls["css/main.css"] = `body {
}

main { 


@@ 35,6 29,8 @@ button {

textarea { 
  width: 100%;
  resize: vertical;
  min-height: 250px;
}

.input-html,


@@ 42,12 38,28 @@ textarea {
  display: block !important; /* tinymce hides this. */
  width: 0;
  height: 0;
  min-height: 0;
  resize: none;
  overflow: hidden;
  position: relative;
  left: 50%;
  top: 100px;
  margin: 0;
  padding: 0;
}

/* To match stylesheet. */

form > legend,
.tox.tox-tinymce { 
  margin-bottom: 16px;
}

details > form {
  margin-top: 16px;
  margin-bottom: 16px;
}

`

	tmpls["html/_footer.html"] = `<footer>


@@ 56,8 68,9 @@ textarea {
`

	tmpls["html/_head.html"] = `<meta charset="utf-8">
<link rel="icon" type="image/x-icon" href="https://favicon.evanjon.es/255/0/0/32/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="https://favicon.evanjon.es/255/0/0/32/favicon.ico" />
<link rel="stylesheet" href="https://andybrewer.github.io/mvp/mvp.css">
`

	tmpls["html/_header.html"] = `<header>


@@ 82,13 95,7 @@ textarea {
    <hr/>
    <article>

      <nav>
        <a href='/contenttype/{{ .Space.ID }}/{{ .ContentType.ID }}'>Back</a>
      </nav>

      <h1>Space: {{ .Space.Name }}</h1>
      <h2>Content Type: {{ .ContentType.Name }}</h2>
      <h3>Content: {{ (.Content.MustValueByName "name").Value }}</h3>
      <h1>{{ .Space.Name }} > {{ .ContentType.Name }} > {{ (.Content.MustValueByName "name").Value }}</h1>

      <details>
        <summary>Update Content</summary>


@@ 127,7 134,7 @@ textarea {

          {{ end }}

          <input type=submit value=Go />
          <input type=submit value=Update />
        </form>
      </details>



@@ 137,7 144,7 @@ textarea {
          <input required type=hidden name=space value="{{ .Space.ID }}" />
          <input required type=hidden name=contenttype value="{{ .ContentType.ID }}" />
          <input required type=hidden name=content value="{{ .Content.ID }}" />
          <input type=submit value=Go />
          <input type=submit value=Delete />
        </form>
      </details>



@@ 158,7 165,7 @@ textarea {

<head>
  {{ template "html/_head.html" }}
  <title>CMS | {{ .Space.Name }} | {{ .ContenType.Name }}</title>
  <title>CMS | {{ .Space.Name }} | {{ .ContentType.Name }}</title>
</head>

<body>


@@ 169,12 176,7 @@ textarea {
    <hr/>
    <article>

      <nav>
        <a href='/space/{{ .Space.ID }}'>Back</a>
      </nav>

      <h1>Space: {{ .Space.Name }}</h1>
      <h2>Content Type: {{ .ContentType.Name }}</h2>
      <h1>{{ .Space.Name }} > {{ .ContentType.Name }}</h1>

      <details>
        <summary>Create a {{ .ContentType.Name }} Content</summary>


@@ 213,26 215,24 @@ textarea {

          {{ end }}

          <input type=submit value=Go />
          <input type=submit value=Create />
        </form>
      </details>

      <details>
        <summary>Browse {{ .ContentType.Name }} Content</summary>
        {{ if .ContentList }}
          <ul>
            {{ range .ContentList }}
              <li> 
                <a href='/content/{{ $.Space.ID }}/{{ $.ContentType.ID }}/{{ .ID }}'>
                  {{ (.MustValueByName "name").Value }}
                </a>
              </li>
            {{ end }}
          </ul>
        {{ else }}
          <p>No content has been created with a content type of {{ .ContentType.Name }}</p>
        {{ end }}
      </details>
      <h2>Browse {{ .ContentType.Name }} Content</h2>
      {{ if .ContentList }}
        <ul>
          {{ range .ContentList }}
            <li> 
              <a href='/content/{{ $.Space.ID }}/{{ $.ContentType.ID }}/{{ .ID }}'>
                {{ (.MustValueByName "name").Value }}
              </a>
            </li>
          {{ end }}
        </ul>
      {{ else }}
        <p>No content has been created with a content type of {{ .ContentType.Name }}</p>
      {{ end }}

    </article>
    <hr/>


@@ 262,6 262,7 @@ textarea {
    <hr/>
    <article>

      <h1>Home</h1>

      {{ if .User }}



@@ 270,30 271,30 @@ textarea {
          <form method=POST action='/space/new' enctype='multipart/form-data'>
            <input required type=text name=name placeholder=name />
            <input required type=text name=desc placeholder=description />
            <input type=submit value=Go />
            <input type=submit value=Create />
          </form>
        </details>

        <details>
          <summary>Available Spaces</summary>
          {{ if .Spaces }}
            <ul>
              {{ range .Spaces }}
              <li><a href="/space/{{ .ID }}">{{ .Name }}</a></li>
              {{ end }}
            </ul>
          {{ else }}
            <p>You haven't created any spaces yet.</p>
          {{ end }}
        </details>

        <details>
          <summary>Logout</summary>
          <form method=POST action='/user/logout' enctype='multipart/form-data'>
            <input type=submit value=Go />
            <input type=submit value=Logout />
          </form>
        </details>

        <br/>

        <h2>Available Spaces</h2>
        {{ if .Spaces }}
          <ul>
            {{ range .Spaces }}
            <li><a href="/space/{{ .ID }}">{{ .Name }}</a></li>
            {{ end }}
          </ul>
        {{ else }}
          <p>You haven't created any spaces yet.</p>
        {{ end }}

      {{ else }}

        <details>


@@ 301,7 302,7 @@ textarea {
          <form method=POST action='/user/login' enctype='multipart/form-data'>
            <input autocomplete=on required type=text name=username placeholder=username autofocus />
            <input autocomplete=on required type=password name=password placeholder=password />
            <input type=submit value=Go />
            <input type=submit value=Login />
          </form>
        </details>



@@ 311,7 312,7 @@ textarea {
            <input autocomplete=on required type=text name=username placeholder=username autofocus />
            <input autocomplete=on required type=password name=password placeholder=password />
            <input autocomplete=on required type=password name=verify placeholder=verify />
            <input type=submit value=Go />
            <input type=submit value=Signup />
          </form>
        </details>



@@ 342,17 343,14 @@ textarea {
    <hr/>
    <article>

      <nav>
        <a href='/'>Back</a>
      </nav>

      <h1>Space: {{ .Space.Name }}</h1>
      <h1>{{ .Space.Name }}</h1>

      <details>
        <summary>Create Content Type</summary>
        <form method=POST action='/contenttype/new' enctype='multipart/form-data'>
          <input required type=hidden name=space value="{{ .Space.ID }}" />
          <input required type=text name=name placeholder="content type name" />
          <legend>Fields</legend>
          <div id='first-fieldset'>
            <input readonly="readonly" required type=text name="field_name_1" value="name" />
            <select readonly="readonly" required name="field_type_1">


@@ 366,22 364,20 @@ textarea {
            </select>
          </div>
          <button id='add-fieldbtn'>Add Another Field</button>
          <input type=submit value=Go />
          <input type=submit value=Create />
        </form>
      </details>

      <details>
        <summary>Browse Content By Type</summary>
        {{ if .ContentTypes }}
          <ul>
            {{ range .ContentTypes }}
              <li><a href='/contenttype/{{ $.Space.ID }}/{{ .ID }}'>{{ .Name }}</a></li>
            {{ end }}
          </ul>
        {{ else }}
          <p>You haven't created any content types yet.</p>
        {{ end }}
      </details>
      <h2>Browse Content By Type</h2>
      {{ if .ContentTypes }}
        <ul>
          {{ range .ContentTypes }}
            <li><a href='/contenttype/{{ $.Space.ID }}/{{ .ID }}'>{{ .Name }}</a></li>
          {{ end }}
        </ul>
      {{ else }}
        <p>You haven't created any content types yet.</p>
      {{ end }}

    </article>
    <hr/>