~repos /gromer

#golang#htmx#ssr

git clone https://pyrossh.dev/repos/gromer.git

gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.


bd2d8258 Peter John

3 years ago
rename ctx
_example/components/page.go DELETED
@@ -1,239 +0,0 @@
1
- package components
2
-
3
- import (
4
- . "github.com/pyros2097/gromer/gsx"
5
- )
6
-
7
- var _ = Css(`
8
- hr {
9
- margin: 20px 0;
10
- border: 0;
11
- border-top: 1px dashed #c5c5c5;
12
- border-bottom: 1px dashed #f7f7f7;
13
- }
14
-
15
- html,
16
- body {
17
- margin: 0;
18
- padding: 0;
19
- }
20
-
21
- button {
22
- margin: 0;
23
- padding: 0;
24
- border: 0;
25
- background: none;
26
- font-size: 100%;
27
- vertical-align: baseline;
28
- font-family: inherit;
29
- font-weight: inherit;
30
- color: inherit;
31
- -webkit-appearance: none;
32
- appearance: none;
33
- -webkit-font-smoothing: antialiased;
34
- -moz-osx-font-smoothing: grayscale;
35
- }
36
-
37
- body {
38
- font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
39
- line-height: 1.4em;
40
- background: #f5f5f5;
41
- color: #4d4d4d;
42
- min-width: 230px;
43
- max-width: 550px;
44
- margin: 0 auto;
45
- -webkit-font-smoothing: antialiased;
46
- -moz-osx-font-smoothing: grayscale;
47
- font-weight: 300;
48
- }
49
-
50
- :focus {
51
- outline: 0;
52
- }
53
-
54
- .hidden {
55
- display: none;
56
- }
57
-
58
- .new-todo,
59
- .edit {
60
- position: relative;
61
- margin: 0;
62
- width: 100%;
63
- font-size: 24px;
64
- font-family: inherit;
65
- font-weight: inherit;
66
- line-height: 1.4em;
67
- border: 0;
68
- color: inherit;
69
- padding: 6px;
70
- border: 1px solid #999;
71
- box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
72
- box-sizing: border-box;
73
- -webkit-font-smoothing: antialiased;
74
- -moz-osx-font-smoothing: grayscale;
75
- }
76
-
77
- .new-todo {
78
- padding: 16px 16px 16px 60px;
79
- border: none;
80
- background: rgba(0, 0, 0, 0.003);
81
- box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
82
- }
83
-
84
- .main {
85
- position: relative;
86
- z-index: 2;
87
- border-top: 1px solid #e6e6e6;
88
- }
89
-
90
- .toggle-all {
91
- text-align: center;
92
- border: none; /* Mobile Safari */
93
- opacity: 0;
94
- position: absolute;
95
- }
96
-
97
- .toggle-all + label {
98
- width: 60px;
99
- height: 34px;
100
- font-size: 0;
101
- position: absolute;
102
- top: -52px;
103
- left: -13px;
104
- -webkit-transform: rotate(90deg);
105
- transform: rotate(90deg);
106
- }
107
-
108
- .toggle-all + label:before {
109
- content: '❯';
110
- font-size: 22px;
111
- color: #e6e6e6;
112
- padding: 10px 27px 10px 27px;
113
- }
114
-
115
- .toggle-all:checked + label:before {
116
- color: #737373;
117
- }
118
-
119
- .footer {
120
- color: #777;
121
- padding: 10px 15px;
122
- height: 20px;
123
- text-align: center;
124
- border-top: 1px solid #e6e6e6;
125
- }
126
-
127
- .footer:before {
128
- content: '';
129
- position: absolute;
130
- right: 0;
131
- bottom: 0;
132
- left: 0;
133
- height: 50px;
134
- overflow: hidden;
135
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2);
136
- }
137
-
138
- .filters {
139
- margin: 0;
140
- padding: 0;
141
- list-style: none;
142
- position: absolute;
143
- right: 0;
144
- left: 0;
145
- }
146
-
147
- .filters li {
148
- display: inline;
149
- }
150
-
151
- .filters li a {
152
- color: inherit;
153
- margin: 3px;
154
- padding: 3px 7px;
155
- text-decoration: none;
156
- border: 1px solid transparent;
157
- border-radius: 3px;
158
- }
159
-
160
- .filters li a:hover {
161
- border-color: rgba(175, 47, 47, 0.1);
162
- }
163
-
164
- .filters li a.selected {
165
- border-color: rgba(175, 47, 47, 0.2);
166
- }
167
-
168
- .clear-completed,
169
- html .clear-completed:active {
170
- float: right;
171
- position: relative;
172
- line-height: 20px;
173
- text-decoration: none;
174
- cursor: pointer;
175
- }
176
-
177
- .clear-completed:hover {
178
- text-decoration: underline;
179
- }
180
-
181
- .info {
182
- margin: 65px auto 0;
183
- color: #bfbfbf;
184
- font-size: 10px;
185
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
186
- text-align: center;
187
- }
188
-
189
- .info p {
190
- line-height: 1;
191
- }
192
-
193
- .info a {
194
- color: inherit;
195
- text-decoration: none;
196
- font-weight: 400;
197
- }
198
-
199
- .info a:hover {
200
- text-decoration: underline;
201
- }
202
-
203
- @media screen and (-webkit-min-device-pixel-ratio: 0) {
204
- .toggle-all {
205
- background: none;
206
- }
207
- }
208
-
209
- @media (max-width: 430px) {
210
- .footer {
211
- height: 50px;
212
- }
213
-
214
- .filters {
215
- bottom: 10px;
216
- }
217
- }
218
- `)
219
-
220
- func Page(ctx Context, title string) *Node {
221
- ctx.Set("title", title)
222
- return ctx.Render(`
223
- <html lang="en">
224
- <head>
225
- <meta charset="UTF-8" />
226
- <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
227
- <meta content="utf-8" http-equiv="encoding" />
228
- <title>{title}</title>
229
- <meta name="description" content="{title}" />
230
- <meta name="author" content="pyrossh" />
231
- <meta name="keywords" content="pyros.sh, pyrossh, gromer" />
232
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, viewport-fit=cover" />
233
- </head>
234
- <body>
235
- {children}
236
- </body>
237
- </html>
238
- `)
239
- }
_example/components/todo.go CHANGED
@@ -8,8 +8,8 @@ import (
8
8
  var _ = Css(`
9
9
  `)
10
10
 
11
- func Todo(ctx Context, todo *todos.Todo) *Node {
11
+ func Todo(c Context, todo *todos.Todo) *Node {
12
- return ctx.Render(`
12
+ return c.Render(`
13
13
  <li id="todo-{todo.ID}" class="{ completed: todo.Completed }">
14
14
  <div class="view">
15
15
  <form hx-target="#todo-{todo.ID}" hx-swap="outerHTML">
_example/containers/TodoCount.go CHANGED
@@ -16,16 +16,16 @@ var _ = Css(`
16
16
  }
17
17
  `)
18
18
 
19
- func TodoCount(ctx Context, filter string) (*Node, error) {
19
+ func TodoCount(c Context, filter string) (*Node, error) {
20
- todos, err := todos.GetAllTodo(ctx, todos.GetAllTodoParams{
20
+ todos, err := todos.GetAllTodo(c, todos.GetAllTodoParams{
21
21
  Filter: filter,
22
22
  Limit: 1000,
23
23
  })
24
24
  if err != nil {
25
25
  return nil, err
26
26
  }
27
- ctx.Set("count", len(todos))
27
+ c.Set("count", len(todos))
28
- return ctx.Render(`
28
+ return c.Render(`
29
29
  <span class="todo-count" id="todo-count" hx-swap-oob="true">
30
30
  <strong>{count}</strong> item left
31
31
  </span>
_example/containers/TodoList.go CHANGED
@@ -127,17 +127,17 @@ var _ = Css(`
127
127
 
128
128
  `)
129
129
 
130
- func TodoList(ctx Context, page int, filter string) (*Node, error) {
130
+ func TodoList(c Context, page int, filter string) (*Node, error) {
131
131
  index := Default(page, 1)
132
- todos, err := todos.GetAllTodo(ctx, todos.GetAllTodoParams{
132
+ todos, err := todos.GetAllTodo(c, todos.GetAllTodoParams{
133
133
  Filter: filter,
134
134
  Limit: index,
135
135
  })
136
136
  if err != nil {
137
137
  return nil, err
138
138
  }
139
- ctx.Set("todos", todos)
139
+ c.Set("todos", todos)
140
- return ctx.Render(`
140
+ return c.Render(`
141
141
  <ul id="todo-list" class="relative" x-for="todo in todos">
142
142
  <Todo />
143
143
  </ul>
_example/main.go CHANGED
@@ -18,7 +18,6 @@ import (
18
18
  )
19
19
 
20
20
  func init() {
21
- gsx.RegisterComponent(components.Page, "title")
22
21
  gsx.RegisterComponent(components.Todo, "todo")
23
22
 
24
23
  gsx.RegisterComponent(containers.TodoCount, "filter")
_example/routes/get.go CHANGED
@@ -8,6 +8,217 @@ import (
8
8
  )
9
9
 
10
10
  var _ = Css(`
11
+ hr {
12
+ margin: 20px 0;
13
+ border: 0;
14
+ border-top: 1px dashed #c5c5c5;
15
+ border-bottom: 1px dashed #f7f7f7;
16
+ }
17
+
18
+ html,
19
+ body {
20
+ margin: 0;
21
+ padding: 0;
22
+ }
23
+
24
+ button {
25
+ margin: 0;
26
+ padding: 0;
27
+ border: 0;
28
+ background: none;
29
+ font-size: 100%;
30
+ vertical-align: baseline;
31
+ font-family: inherit;
32
+ font-weight: inherit;
33
+ color: inherit;
34
+ -webkit-appearance: none;
35
+ appearance: none;
36
+ -webkit-font-smoothing: antialiased;
37
+ -moz-osx-font-smoothing: grayscale;
38
+ }
39
+
40
+ body {
41
+ font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
42
+ line-height: 1.4em;
43
+ background: #f5f5f5;
44
+ color: #4d4d4d;
45
+ min-width: 230px;
46
+ max-width: 550px;
47
+ margin: 0 auto;
48
+ -webkit-font-smoothing: antialiased;
49
+ -moz-osx-font-smoothing: grayscale;
50
+ font-weight: 300;
51
+ }
52
+
53
+ :focus {
54
+ outline: 0;
55
+ }
56
+
57
+ .hidden {
58
+ display: none;
59
+ }
60
+
61
+ .new-todo,
62
+ .edit {
63
+ position: relative;
64
+ margin: 0;
65
+ width: 100%;
66
+ font-size: 24px;
67
+ font-family: inherit;
68
+ font-weight: inherit;
69
+ line-height: 1.4em;
70
+ border: 0;
71
+ color: inherit;
72
+ padding: 6px;
73
+ border: 1px solid #999;
74
+ box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
75
+ box-sizing: border-box;
76
+ -webkit-font-smoothing: antialiased;
77
+ -moz-osx-font-smoothing: grayscale;
78
+ }
79
+
80
+ .new-todo {
81
+ padding: 16px 16px 16px 60px;
82
+ border: none;
83
+ background: rgba(0, 0, 0, 0.003);
84
+ box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
85
+ }
86
+
87
+ .main {
88
+ position: relative;
89
+ z-index: 2;
90
+ border-top: 1px solid #e6e6e6;
91
+ }
92
+
93
+ .toggle-all {
94
+ text-align: center;
95
+ border: none; /* Mobile Safari */
96
+ opacity: 0;
97
+ position: absolute;
98
+ }
99
+
100
+ .toggle-all + label {
101
+ width: 60px;
102
+ height: 34px;
103
+ font-size: 0;
104
+ position: absolute;
105
+ top: -52px;
106
+ left: -13px;
107
+ -webkit-transform: rotate(90deg);
108
+ transform: rotate(90deg);
109
+ }
110
+
111
+ .toggle-all + label:before {
112
+ content: '❯';
113
+ font-size: 22px;
114
+ color: #e6e6e6;
115
+ padding: 10px 27px 10px 27px;
116
+ }
117
+
118
+ .toggle-all:checked + label:before {
119
+ color: #737373;
120
+ }
121
+
122
+ .footer {
123
+ color: #777;
124
+ padding: 10px 15px;
125
+ height: 20px;
126
+ text-align: center;
127
+ border-top: 1px solid #e6e6e6;
128
+ }
129
+
130
+ .footer:before {
131
+ content: '';
132
+ position: absolute;
133
+ right: 0;
134
+ bottom: 0;
135
+ left: 0;
136
+ height: 50px;
137
+ overflow: hidden;
138
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2);
139
+ }
140
+
141
+ .filters {
142
+ margin: 0;
143
+ padding: 0;
144
+ list-style: none;
145
+ position: absolute;
146
+ right: 0;
147
+ left: 0;
148
+ }
149
+
150
+ .filters li {
151
+ display: inline;
152
+ }
153
+
154
+ .filters li a {
155
+ color: inherit;
156
+ margin: 3px;
157
+ padding: 3px 7px;
158
+ text-decoration: none;
159
+ border: 1px solid transparent;
160
+ border-radius: 3px;
161
+ }
162
+
163
+ .filters li a:hover {
164
+ border-color: rgba(175, 47, 47, 0.1);
165
+ }
166
+
167
+ .filters li a.selected {
168
+ border-color: rgba(175, 47, 47, 0.2);
169
+ }
170
+
171
+ .clear-completed,
172
+ html .clear-completed:active {
173
+ float: right;
174
+ position: relative;
175
+ line-height: 20px;
176
+ text-decoration: none;
177
+ cursor: pointer;
178
+ }
179
+
180
+ .clear-completed:hover {
181
+ text-decoration: underline;
182
+ }
183
+
184
+ .info {
185
+ margin: 65px auto 0;
186
+ color: #bfbfbf;
187
+ font-size: 10px;
188
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
189
+ text-align: center;
190
+ }
191
+
192
+ .info p {
193
+ line-height: 1;
194
+ }
195
+
196
+ .info a {
197
+ color: inherit;
198
+ text-decoration: none;
199
+ font-weight: 400;
200
+ }
201
+
202
+ .info a:hover {
203
+ text-decoration: underline;
204
+ }
205
+
206
+ @media screen and (-webkit-min-device-pixel-ratio: 0) {
207
+ .toggle-all {
208
+ background: none;
209
+ }
210
+ }
211
+
212
+ @media (max-width: 430px) {
213
+ .footer {
214
+ height: 50px;
215
+ }
216
+
217
+ .filters {
218
+ bottom: 10px;
219
+ }
220
+ }
221
+
11
222
  .todoapp {
12
223
  background: #fff;
13
224
  margin: 130px 0 40px 0;
@@ -78,11 +289,11 @@ func IndexPage() {
78
289
  // <meta name="keywords" content="pyros.sh, pyrossh, gromer" />
79
290
  // <meta />
80
291
 
81
- func GET(h Context, params GetParams) (*Node, int, error) {
292
+ func GET(c Context, params GetParams) (*Node, int, error) {
82
- h.Meta("title", "Todos")
293
+ c.Meta("title", "Todos")
83
- h.Set("page", params.Page)
294
+ c.Set("page", params.Page)
84
- h.Set("filter", params.Filter)
295
+ c.Set("filter", params.Filter)
85
- return h.Render(`
296
+ return c.Render(`
86
297
  <section class="todoapp">
87
298
  <header class="header">
88
299
  <h1>todos</h1>
_example/routes/post.go CHANGED
@@ -14,9 +14,9 @@ type PostParams struct {
14
14
  Text string `json:"text"`
15
15
  }
16
16
 
17
- func POST(ctx Context, params PostParams) (*Node, int, error) {
17
+ func POST(c Context, params PostParams) (*Node, int, error) {
18
18
  if params.Intent == "clear_completed" {
19
- allTodos, err := todos.GetAllTodo(ctx, todos.GetAllTodoParams{
19
+ allTodos, err := todos.GetAllTodo(c, todos.GetAllTodoParams{
20
20
  Filter: "all",
21
21
  Limit: 1000,
22
22
  })
@@ -25,46 +25,46 @@ func POST(ctx Context, params PostParams) (*Node, int, error) {
25
25
  }
26
26
  for _, t := range allTodos {
27
27
  if t.Completed {
28
- _, err := todos.DeleteTodo(ctx, t.ID)
28
+ _, err := todos.DeleteTodo(c, t.ID)
29
29
  if err != nil {
30
30
  return nil, 500, err
31
31
  }
32
32
  }
33
33
  }
34
- return ctx.Render(`
34
+ return c.Render(`
35
35
  <TodoList id="todo-list" filter="all" page="1"></TodoList>
36
36
  <TodoCount filter="all" page="1"></TodoCount>
37
37
  `), 200, nil
38
38
  } else if params.Intent == "create" {
39
- todo, err := todos.CreateTodo(ctx, params.Text)
39
+ todo, err := todos.CreateTodo(c, params.Text)
40
40
  if err != nil {
41
41
  return nil, 500, err
42
42
  }
43
- ctx.Set("todo", todo)
43
+ c.Set("todo", todo)
44
- return ctx.Render(`
44
+ return c.Render(`
45
45
  <Todo todo=todo></Todo>
46
46
  <TodoCount filter="all" page="1"></TodoCount>
47
47
  `), 200, nil
48
48
  } else if params.Intent == "delete" {
49
- _, err := todos.DeleteTodo(ctx, params.ID)
49
+ _, err := todos.DeleteTodo(c, params.ID)
50
50
  if err != nil {
51
51
  return nil, 500, err
52
52
  }
53
53
  return nil, 200, nil
54
54
  } else if params.Intent == "complete" {
55
- todo, err := todos.GetTodo(ctx, params.ID)
55
+ todo, err := todos.GetTodo(c, params.ID)
56
56
  if err != nil {
57
57
  return nil, 500, err
58
58
  }
59
- _, err = todos.UpdateTodo(ctx, params.ID, todos.UpdateTodoParams{
59
+ _, err = todos.UpdateTodo(c, params.ID, todos.UpdateTodoParams{
60
60
  Text: todo.Text,
61
61
  Completed: !todo.Completed,
62
62
  })
63
63
  if err != nil {
64
64
  return nil, 500, err
65
65
  }
66
- ctx.Set("todo", todo)
66
+ c.Set("todo", todo)
67
- return ctx.Render(`
67
+ return c.Render(`
68
68
  {{#Todo todo=todo}}{{/Todo}}
69
69
  `), 200, nil
70
70
  }