granule 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +21 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +8 -7
- data/Gemfile +2 -0
- data/README.md +112 -13
- data/Rakefile +2 -0
- data/bin/console +1 -0
- data/exe/granule +1 -2
- data/granule.gemspec +2 -0
- data/lib/granule/cli.rb +19 -4
- data/lib/granule/feature/devise_semantic/devise.en.yml +65 -0
- data/lib/granule/feature/devise_semantic/devise.rb +303 -0
- data/lib/granule/feature/devise_semantic/devise_create_users.rb +43 -0
- data/lib/granule/feature/devise_semantic/user.rb +8 -0
- data/lib/granule/feature/devise_semantic/views/users/confirmations/new.html.erb +16 -0
- data/lib/granule/feature/devise_semantic/views/users/mailer/confirmation_instructions.html.erb +5 -0
- data/lib/granule/feature/devise_semantic/views/users/mailer/email_changed.html.erb +7 -0
- data/lib/granule/feature/devise_semantic/views/users/mailer/password_change.html.erb +3 -0
- data/lib/granule/feature/devise_semantic/views/users/mailer/reset_password_instructions.html.erb +8 -0
- data/lib/granule/feature/devise_semantic/views/users/mailer/unlock_instructions.html.erb +7 -0
- data/lib/granule/feature/devise_semantic/views/users/passwords/edit.html.erb +25 -0
- data/lib/granule/feature/devise_semantic/views/users/passwords/new.html.erb +18 -0
- data/lib/granule/feature/devise_semantic/views/users/registrations/edit.html.erb +45 -0
- data/lib/granule/feature/devise_semantic/views/users/registrations/new.html.erb +31 -0
- data/lib/granule/feature/devise_semantic/views/users/sessions/new.html.erb +37 -0
- data/lib/granule/feature/devise_semantic/views/users/shared/_error_messages.html.erb +14 -0
- data/lib/granule/feature/devise_semantic/views/users/shared/_links.html.erb +25 -0
- data/lib/granule/feature/devise_semantic/views/users/show.html.erb +22 -0
- data/lib/granule/feature/devise_semantic/views/users/unlocks/new.html.erb +16 -0
- data/lib/granule/feature/devise_semantic.rb +58 -0
- data/lib/granule/feature/semantic_react/hello_react.jsx +340 -0
- data/lib/granule/feature/semantic_react/homes_controller.rb +5 -0
- data/lib/granule/feature/semantic_react/index.html.erb +0 -0
- data/lib/granule/feature/semantic_react.rb +50 -0
- data/lib/granule/new/base/.dockerignore.tt +5 -0
- data/lib/granule/new/base/.gitignore.tt +33 -0
- data/lib/granule/{templates → new/base}/.rubocop.yml.tt +0 -0
- data/lib/granule/new/base/Dockerfile.dev.tt +34 -0
- data/lib/granule/{templates → new/base}/Gemfile.tt +5 -8
- data/lib/granule/new/base/README.md.tt +21 -0
- data/lib/granule/new/base/database.yml.tt +21 -0
- data/lib/granule/new/base/docker-compose.yml.tt +83 -0
- data/lib/granule/new/base.rb +19 -0
- data/lib/granule/version.rb +4 -2
- data/lib/granule.rb +2 -1
- metadata +38 -8
- data/Gemfile.lock +0 -169
- data/lib/granule/template.rb +0 -10
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Granule
|
4
|
+
module Feature
|
5
|
+
class DeviseSemantic < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
APPLICATION_HTML_ERB_PATH = './app/views/layouts/application.html.erb'
|
9
|
+
APPLICATION_PATH = './config/application.rb'
|
10
|
+
DEVELOPMENT_PATH = './config/environments/development.rb'
|
11
|
+
ROUTES_PATH = './config/routes.rb'
|
12
|
+
|
13
|
+
no_commands do
|
14
|
+
def call
|
15
|
+
check_files
|
16
|
+
|
17
|
+
copy_file 'devise.rb', './config/initializers/devise.rb'
|
18
|
+
copy_file 'user.rb', './app/models/user.rb'
|
19
|
+
copy_file 'devise.en.yml', './config/locales/devise.en.yml'
|
20
|
+
copy_file 'devise_create_users.rb', "./db/migrate/#{Time.now.strftime('%Y%m%d%H%m%S')}_devise_create_users.rb"
|
21
|
+
|
22
|
+
uncomment_lines APPLICATION_PATH, %r{sprockets/railtie}
|
23
|
+
directory 'views', './app/views'
|
24
|
+
insert_into_file ROUTES_PATH, "\tdevise_for :users\n",
|
25
|
+
after: "Rails.application.routes.draw do\n"
|
26
|
+
insert_into_file APPLICATION_HTML_ERB_PATH,
|
27
|
+
"\t\t<% if current_user %>\n"\
|
28
|
+
"\t\t\t<div class=\"ui pointing secondary menu\">\n"\
|
29
|
+
"\t\t\t\t<a class=\"active item\" href=\"/\">Home</a>\n"\
|
30
|
+
"\t\t\t\t<div class=\"right menu\">\n"\
|
31
|
+
"\t\t\t\t\t<%= link_to 'Logout', destroy_user_session_url, "\
|
32
|
+
"method: :delete, class: 'item' %>\n"\
|
33
|
+
"\t\t\t\t</div>\n"\
|
34
|
+
"\t\t\t</div>\n"\
|
35
|
+
"\t\t<% end %>\n",
|
36
|
+
after: "<body>\n"
|
37
|
+
|
38
|
+
insert_into_file DEVELOPMENT_PATH,
|
39
|
+
"\tconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }\n"\
|
40
|
+
"\tconfig.action_mailer.delivery_method = :letter_opener_web\n",
|
41
|
+
after: "Rails.application.configure do\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.source_root
|
46
|
+
"#{File.dirname(__FILE__)}/devise_semantic"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def check_files
|
52
|
+
[APPLICATION_HTML_ERB_PATH, APPLICATION_PATH, DEVELOPMENT_PATH, ROUTES_PATH].each do |file_path|
|
53
|
+
raise Granule::Error, "#{file_path} doesn't exist" unless File.file?(file_path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,340 @@
|
|
1
|
+
// Run this example by adding <%= javascript_pack_tag 'hello_react' %> to the head of your layout file,
|
2
|
+
// like app/views/layouts/application.html.erb. All it does is render <div>Hello React</div> at the bottom
|
3
|
+
// of the page.
|
4
|
+
|
5
|
+
import ReactDOM from 'react-dom'
|
6
|
+
import React, { Component } from 'react'
|
7
|
+
import PropTypes from 'prop-types'
|
8
|
+
import {
|
9
|
+
Button,
|
10
|
+
Container,
|
11
|
+
Divider,
|
12
|
+
Grid,
|
13
|
+
Header,
|
14
|
+
Icon,
|
15
|
+
Image,
|
16
|
+
List,
|
17
|
+
Menu,
|
18
|
+
Responsive,
|
19
|
+
Segment,
|
20
|
+
Sidebar,
|
21
|
+
Visibility,
|
22
|
+
} from 'semantic-ui-react'
|
23
|
+
|
24
|
+
const getWidth = () => {
|
25
|
+
const isSSR = typeof window === 'undefined'
|
26
|
+
|
27
|
+
return isSSR ? Responsive.onlyTablet.minWidth : window.innerWidth
|
28
|
+
}
|
29
|
+
|
30
|
+
const HomepageHeading = ({ mobile }) => (
|
31
|
+
<Container text>
|
32
|
+
<Header
|
33
|
+
as='h1'
|
34
|
+
content='Imagine-a-Company'
|
35
|
+
inverted
|
36
|
+
style={{
|
37
|
+
fontSize: mobile ? '2em' : '4em',
|
38
|
+
fontWeight: 'normal',
|
39
|
+
marginBottom: 0,
|
40
|
+
marginTop: mobile ? '1.5em' : '3em',
|
41
|
+
}}
|
42
|
+
/>
|
43
|
+
<Header
|
44
|
+
as='h2'
|
45
|
+
content='Do whatever you want when you want to.'
|
46
|
+
inverted
|
47
|
+
style={{
|
48
|
+
fontSize: mobile ? '1.5em' : '1.7em',
|
49
|
+
fontWeight: 'normal',
|
50
|
+
marginTop: mobile ? '0.5em' : '1.5em',
|
51
|
+
}}
|
52
|
+
/>
|
53
|
+
<Button primary size='huge'>
|
54
|
+
Get Started
|
55
|
+
<Icon name='right arrow' />
|
56
|
+
</Button>
|
57
|
+
</Container>
|
58
|
+
)
|
59
|
+
|
60
|
+
HomepageHeading.propTypes = {
|
61
|
+
mobile: PropTypes.bool,
|
62
|
+
}
|
63
|
+
|
64
|
+
/* Heads up!
|
65
|
+
* Neither Semantic UI nor Semantic UI React offer a responsive navbar, however, it can be implemented easily.
|
66
|
+
* It can be more complicated, but you can create really flexible markup.
|
67
|
+
*/
|
68
|
+
class DesktopContainer extends Component {
|
69
|
+
state = {}
|
70
|
+
|
71
|
+
hideFixedMenu = () => this.setState({ fixed: false })
|
72
|
+
showFixedMenu = () => this.setState({ fixed: true })
|
73
|
+
|
74
|
+
render() {
|
75
|
+
const { children } = this.props
|
76
|
+
const { fixed } = this.state
|
77
|
+
|
78
|
+
return (
|
79
|
+
<Responsive getWidth={getWidth} minWidth={Responsive.onlyTablet.minWidth}>
|
80
|
+
<Visibility
|
81
|
+
once={false}
|
82
|
+
onBottomPassed={this.showFixedMenu}
|
83
|
+
onBottomPassedReverse={this.hideFixedMenu}
|
84
|
+
>
|
85
|
+
<Segment
|
86
|
+
inverted
|
87
|
+
textAlign='center'
|
88
|
+
style={{ minHeight: 700, padding: '1em 0em' }}
|
89
|
+
vertical
|
90
|
+
>
|
91
|
+
<Menu
|
92
|
+
fixed={fixed ? 'top' : null}
|
93
|
+
inverted={!fixed}
|
94
|
+
pointing={!fixed}
|
95
|
+
secondary={!fixed}
|
96
|
+
size='large'
|
97
|
+
>
|
98
|
+
<Container>
|
99
|
+
<Menu.Item as='a' active>
|
100
|
+
Home
|
101
|
+
</Menu.Item>
|
102
|
+
<Menu.Item as='a'>Work</Menu.Item>
|
103
|
+
<Menu.Item as='a'>Company</Menu.Item>
|
104
|
+
<Menu.Item as='a'>Careers</Menu.Item>
|
105
|
+
<Menu.Item position='right'>
|
106
|
+
<Button as='a' inverted={!fixed}>
|
107
|
+
Log in
|
108
|
+
</Button>
|
109
|
+
<Button as='a' inverted={!fixed} primary={fixed} style={{ marginLeft: '0.5em' }}>
|
110
|
+
Sign Up
|
111
|
+
</Button>
|
112
|
+
</Menu.Item>
|
113
|
+
</Container>
|
114
|
+
</Menu>
|
115
|
+
<HomepageHeading />
|
116
|
+
</Segment>
|
117
|
+
</Visibility>
|
118
|
+
|
119
|
+
{children}
|
120
|
+
</Responsive>
|
121
|
+
)
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
DesktopContainer.propTypes = {
|
126
|
+
children: PropTypes.node,
|
127
|
+
}
|
128
|
+
|
129
|
+
class MobileContainer extends Component {
|
130
|
+
state = {}
|
131
|
+
|
132
|
+
handleSidebarHide = () => this.setState({ sidebarOpened: false })
|
133
|
+
|
134
|
+
handleToggle = () => this.setState({ sidebarOpened: true })
|
135
|
+
|
136
|
+
render() {
|
137
|
+
const { children } = this.props
|
138
|
+
const { sidebarOpened } = this.state
|
139
|
+
|
140
|
+
return (
|
141
|
+
<Responsive
|
142
|
+
as={Sidebar.Pushable}
|
143
|
+
getWidth={getWidth}
|
144
|
+
maxWidth={Responsive.onlyMobile.maxWidth}
|
145
|
+
>
|
146
|
+
<Sidebar
|
147
|
+
as={Menu}
|
148
|
+
animation='push'
|
149
|
+
inverted
|
150
|
+
onHide={this.handleSidebarHide}
|
151
|
+
vertical
|
152
|
+
visible={sidebarOpened}
|
153
|
+
>
|
154
|
+
<Menu.Item as='a' active>
|
155
|
+
Home
|
156
|
+
</Menu.Item>
|
157
|
+
<Menu.Item as='a'>Work</Menu.Item>
|
158
|
+
<Menu.Item as='a'>Company</Menu.Item>
|
159
|
+
<Menu.Item as='a'>Careers</Menu.Item>
|
160
|
+
<Menu.Item as='a'>Log in</Menu.Item>
|
161
|
+
<Menu.Item as='a'>Sign Up</Menu.Item>
|
162
|
+
</Sidebar>
|
163
|
+
|
164
|
+
<Sidebar.Pusher dimmed={sidebarOpened}>
|
165
|
+
<Segment
|
166
|
+
inverted
|
167
|
+
textAlign='center'
|
168
|
+
style={{ minHeight: 350, padding: '1em 0em' }}
|
169
|
+
vertical
|
170
|
+
>
|
171
|
+
<Container>
|
172
|
+
<Menu inverted pointing secondary size='large'>
|
173
|
+
<Menu.Item onClick={this.handleToggle}>
|
174
|
+
<Icon name='sidebar' />
|
175
|
+
</Menu.Item>
|
176
|
+
<Menu.Item position='right'>
|
177
|
+
<Button as='a' inverted>
|
178
|
+
Log in
|
179
|
+
</Button>
|
180
|
+
<Button as='a' inverted style={{ marginLeft: '0.5em' }}>
|
181
|
+
Sign Up
|
182
|
+
</Button>
|
183
|
+
</Menu.Item>
|
184
|
+
</Menu>
|
185
|
+
</Container>
|
186
|
+
<HomepageHeading mobile />
|
187
|
+
</Segment>
|
188
|
+
|
189
|
+
{children}
|
190
|
+
</Sidebar.Pusher>
|
191
|
+
</Responsive>
|
192
|
+
)
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
MobileContainer.propTypes = {
|
197
|
+
children: PropTypes.node,
|
198
|
+
}
|
199
|
+
|
200
|
+
const ResponsiveContainer = ({ children }) => (
|
201
|
+
<div>
|
202
|
+
<DesktopContainer>{children}</DesktopContainer>
|
203
|
+
<MobileContainer>{children}</MobileContainer>
|
204
|
+
</div>
|
205
|
+
)
|
206
|
+
|
207
|
+
ResponsiveContainer.propTypes = {
|
208
|
+
children: PropTypes.node,
|
209
|
+
}
|
210
|
+
|
211
|
+
const HomepageLayout = () => (
|
212
|
+
<ResponsiveContainer>
|
213
|
+
<Segment style={{ padding: '8em 0em' }} vertical>
|
214
|
+
<Grid container stackable verticalAlign='middle'>
|
215
|
+
<Grid.Row>
|
216
|
+
<Grid.Column width={8}>
|
217
|
+
<Header as='h3' style={{ fontSize: '2em' }}>
|
218
|
+
We Help Companies and Companions
|
219
|
+
</Header>
|
220
|
+
<p style={{ fontSize: '1.33em' }}>
|
221
|
+
We can give your company superpowers to do things that they never thought possible.
|
222
|
+
Let us delight your customers and empower your needs... through pure data analytics.
|
223
|
+
</p>
|
224
|
+
<Header as='h3' style={{ fontSize: '2em' }}>
|
225
|
+
We Make Bananas That Can Dance
|
226
|
+
</Header>
|
227
|
+
<p style={{ fontSize: '1.33em' }}>
|
228
|
+
Yes that's right, you thought it was the stuff of dreams, but even bananas can be
|
229
|
+
bioengineered.
|
230
|
+
</p>
|
231
|
+
</Grid.Column>
|
232
|
+
<Grid.Column floated='right' width={6}>
|
233
|
+
<Image bordered rounded size='large' src='https://via.placeholder.com/500x300.png' />
|
234
|
+
</Grid.Column>
|
235
|
+
</Grid.Row>
|
236
|
+
<Grid.Row>
|
237
|
+
<Grid.Column textAlign='center'>
|
238
|
+
<Button size='huge'>Check Them Out</Button>
|
239
|
+
</Grid.Column>
|
240
|
+
</Grid.Row>
|
241
|
+
</Grid>
|
242
|
+
</Segment>
|
243
|
+
<Segment style={{ padding: '0em' }} vertical>
|
244
|
+
<Grid celled='internally' columns='equal' stackable>
|
245
|
+
<Grid.Row textAlign='center'>
|
246
|
+
<Grid.Column style={{ paddingBottom: '5em', paddingTop: '5em' }}>
|
247
|
+
<Header as='h3' style={{ fontSize: '2em' }}>
|
248
|
+
"What a Company"
|
249
|
+
</Header>
|
250
|
+
<p style={{ fontSize: '1.33em' }}>That is what they all say about us</p>
|
251
|
+
</Grid.Column>
|
252
|
+
<Grid.Column style={{ paddingBottom: '5em', paddingTop: '5em' }}>
|
253
|
+
<Header as='h3' style={{ fontSize: '2em' }}>
|
254
|
+
"I shouldn't have gone with their competitor."
|
255
|
+
</Header>
|
256
|
+
<p style={{ fontSize: '1.33em' }}>
|
257
|
+
<Image avatar src='https://via.placeholder.com/500x300.png' />
|
258
|
+
<b>Nan</b> Chief Fun Officer Acme Toys
|
259
|
+
</p>
|
260
|
+
</Grid.Column>
|
261
|
+
</Grid.Row>
|
262
|
+
</Grid>
|
263
|
+
</Segment>
|
264
|
+
<Segment style={{ padding: '8em 0em' }} vertical>
|
265
|
+
<Container text>
|
266
|
+
<Header as='h3' style={{ fontSize: '2em' }}>
|
267
|
+
Breaking The Grid, Grabs Your Attention
|
268
|
+
</Header>
|
269
|
+
<p style={{ fontSize: '1.33em' }}>
|
270
|
+
Instead of focusing on content creation and hard work, we have learned how to master the
|
271
|
+
art of doing nothing by providing massive amounts of whitespace and generic content that
|
272
|
+
can seem massive, monolithic and worth your attention.
|
273
|
+
</p>
|
274
|
+
<Button as='a' size='large'>
|
275
|
+
Read More
|
276
|
+
</Button>
|
277
|
+
<Divider
|
278
|
+
as='h4'
|
279
|
+
className='header'
|
280
|
+
horizontal
|
281
|
+
style={{ margin: '3em 0em', textTransform: 'uppercase' }}
|
282
|
+
>
|
283
|
+
<a href='#'>Case Studies</a>
|
284
|
+
</Divider>
|
285
|
+
<Header as='h3' style={{ fontSize: '2em' }}>
|
286
|
+
Did We Tell You About Our Bananas?
|
287
|
+
</Header>
|
288
|
+
<p style={{ fontSize: '1.33em' }}>
|
289
|
+
Yes I know you probably disregarded the earlier boasts as non-sequitur filler content, but
|
290
|
+
it's really true. It took years of gene splicing and combinatory DNA research, but our
|
291
|
+
bananas can really dance.
|
292
|
+
</p>
|
293
|
+
<Button as='a' size='large'>
|
294
|
+
I'm Still Quite Interested
|
295
|
+
</Button>
|
296
|
+
</Container>
|
297
|
+
</Segment>
|
298
|
+
<Segment inverted vertical style={{ padding: '5em 0em' }}>
|
299
|
+
<Container>
|
300
|
+
<Grid divided inverted stackable>
|
301
|
+
<Grid.Row>
|
302
|
+
<Grid.Column width={3}>
|
303
|
+
<Header inverted as='h4' content='About' />
|
304
|
+
<List link inverted>
|
305
|
+
<List.Item as='a'>Sitemap</List.Item>
|
306
|
+
<List.Item as='a'>Contact Us</List.Item>
|
307
|
+
<List.Item as='a'>Religious Ceremonies</List.Item>
|
308
|
+
<List.Item as='a'>Gazebo Plans</List.Item>
|
309
|
+
</List>
|
310
|
+
</Grid.Column>
|
311
|
+
<Grid.Column width={3}>
|
312
|
+
<Header inverted as='h4' content='Services' />
|
313
|
+
<List link inverted>
|
314
|
+
<List.Item as='a'>Banana Pre-Order</List.Item>
|
315
|
+
<List.Item as='a'>DNA FAQ</List.Item>
|
316
|
+
<List.Item as='a'>How To Access</List.Item>
|
317
|
+
<List.Item as='a'>Favorite X-Men</List.Item>
|
318
|
+
</List>
|
319
|
+
</Grid.Column>
|
320
|
+
<Grid.Column width={7}>
|
321
|
+
<Header as='h4' inverted>
|
322
|
+
Footer Header
|
323
|
+
</Header>
|
324
|
+
<p>
|
325
|
+
Extra space for a call to action inside the footer that could help re-engage users.
|
326
|
+
</p>
|
327
|
+
</Grid.Column>
|
328
|
+
</Grid.Row>
|
329
|
+
</Grid>
|
330
|
+
</Container>
|
331
|
+
</Segment>
|
332
|
+
</ResponsiveContainer>
|
333
|
+
)
|
334
|
+
|
335
|
+
document.addEventListener('DOMContentLoaded', () => {
|
336
|
+
ReactDOM.render(
|
337
|
+
<HomepageLayout />,
|
338
|
+
document.body.appendChild(document.createElement('div')),
|
339
|
+
)
|
340
|
+
})
|
File without changes
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Granule
|
4
|
+
module Feature
|
5
|
+
class SemanticReact < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
APPLICATION_JS_PATH = './app/javascript/packs/application.js'
|
9
|
+
APPLICATION_HTML_ERB_PATH = './app/views/layouts/application.html.erb'
|
10
|
+
PACKAGE_JSON_PATH = './package.json'
|
11
|
+
ROUTES_PATH = './config/routes.rb'
|
12
|
+
|
13
|
+
no_commands do
|
14
|
+
def call
|
15
|
+
check_files
|
16
|
+
|
17
|
+
copy_file 'homes_controller.rb', './app/controllers/homes_controller.rb'
|
18
|
+
copy_file 'hello_react.jsx', './app/javascript/packs/hello_react.jsx', force: true
|
19
|
+
copy_file 'index.html.erb', './app/views/homes/index.html.erb'
|
20
|
+
|
21
|
+
insert_into_file APPLICATION_JS_PATH,
|
22
|
+
"import 'semantic-ui-css/semantic.min.css';\n\n",
|
23
|
+
before: 'require("@rails/ujs").start()'
|
24
|
+
|
25
|
+
insert_into_file APPLICATION_HTML_ERB_PATH,
|
26
|
+
"\t\t<%= javascript_pack_tag 'hello_react' %>",
|
27
|
+
after: "<%= javascript_pack_tag 'application' %>\n"
|
28
|
+
|
29
|
+
insert_into_file ROUTES_PATH, "\troot 'homes#index'\n", after: "Rails.application.routes.draw do\n"
|
30
|
+
|
31
|
+
insert_into_file PACKAGE_JSON_PATH,
|
32
|
+
"\t\t\"semantic-ui-css\": \"^2.4.1\",\n\t\t\"semantic-ui-react\": \"^0.88.1\",\n",
|
33
|
+
after: "\"dependencies\": {\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.source_root
|
38
|
+
"#{File.dirname(__FILE__)}/semantic_react"
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def check_files
|
44
|
+
[APPLICATION_JS_PATH, ROUTES_PATH, APPLICATION_HTML_ERB_PATH, PACKAGE_JSON_PATH].each do |file_path|
|
45
|
+
raise Granule::Error, "#{file_path} doesn't exist" unless File.file?(file_path)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
|
2
|
+
#
|
3
|
+
# If you find yourself ignoring temporary files generated by your text editor
|
4
|
+
# or operating system, you probably want to add a global ignore instead:
|
5
|
+
# git config --global core.excludesfile '~/.gitignore_global'
|
6
|
+
|
7
|
+
# Ignore bundler config.
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore all logfiles and tempfiles.
|
11
|
+
/log/*
|
12
|
+
/tmp/*
|
13
|
+
!/log/.keep
|
14
|
+
!/tmp/.keep
|
15
|
+
|
16
|
+
# Ignore uploaded files in development.
|
17
|
+
/storage/*
|
18
|
+
!/storage/.keep
|
19
|
+
|
20
|
+
/public/assets
|
21
|
+
.byebug_history
|
22
|
+
|
23
|
+
# Ignore master key for decrypting credentials and more.
|
24
|
+
/config/master.key
|
25
|
+
|
26
|
+
/public/packs
|
27
|
+
/public/packs-test
|
28
|
+
/node_modules
|
29
|
+
/yarn-error.log
|
30
|
+
yarn-debug.log*
|
31
|
+
.yarn-integrity
|
32
|
+
|
33
|
+
.psqlrc
|
File without changes
|
@@ -0,0 +1,34 @@
|
|
1
|
+
ARG RUBY_VERSION
|
2
|
+
ARG ALPINE_VERSION
|
3
|
+
FROM ruby:$RUBY_VERSION-alpine$ALPINE_VERSION
|
4
|
+
|
5
|
+
ARG BUNDLER_VERSION
|
6
|
+
|
7
|
+
RUN apk add --update --no-cache \
|
8
|
+
bash \
|
9
|
+
build-base \
|
10
|
+
postgresql-client \
|
11
|
+
postgresql-dev \
|
12
|
+
nodejs-current \
|
13
|
+
git \
|
14
|
+
imagemagick \
|
15
|
+
tzdata
|
16
|
+
|
17
|
+
RUN apk add --no-cache yarn --repository="http://dl-cdn.alpinelinux.org/alpine/edge/community"
|
18
|
+
|
19
|
+
# Configure bundler and PATH
|
20
|
+
ENV LANG=C.UTF-8 \
|
21
|
+
GEM_HOME=/bundle \
|
22
|
+
BUNDLE_JOBS=4 \
|
23
|
+
BUNDLE_RETRY=3
|
24
|
+
ENV BUNDLE_PATH $GEM_HOME
|
25
|
+
ENV BUNDLE_APP_CONFIG=$BUNDLE_PATH \
|
26
|
+
BUNDLE_BIN=$BUNDLE_PATH/bin
|
27
|
+
ENV PATH /app/bin:$BUNDLE_BIN:$PATH
|
28
|
+
|
29
|
+
RUN gem update --system && \
|
30
|
+
gem install bundler:$BUNDLER_VERSION
|
31
|
+
|
32
|
+
RUN mkdir -p /app
|
33
|
+
|
34
|
+
WORKDIR /app
|
@@ -14,7 +14,7 @@ gem 'dry-matcher'
|
|
14
14
|
gem 'dry-monads'
|
15
15
|
|
16
16
|
# Validation
|
17
|
-
gem 'dry-validation'
|
17
|
+
gem 'dry-validation'
|
18
18
|
|
19
19
|
# I18n for js
|
20
20
|
gem 'i18n-js'
|
@@ -25,15 +25,15 @@ gem 'mini_magick'
|
|
25
25
|
# Database adapter
|
26
26
|
gem 'pg'
|
27
27
|
|
28
|
+
# Data migrator
|
29
|
+
gem 'data_migrate'
|
30
|
+
|
28
31
|
# Ruby Server
|
29
32
|
gem 'puma'
|
30
33
|
|
31
34
|
# Framework
|
32
35
|
gem 'rails'
|
33
36
|
|
34
|
-
# React rails monolith
|
35
|
-
gem 'react-rails'
|
36
|
-
|
37
37
|
# User roles management
|
38
38
|
gem 'rolify'
|
39
39
|
|
@@ -42,7 +42,7 @@ gem 'webpacker'
|
|
42
42
|
|
43
43
|
group :development do
|
44
44
|
gem 'better_errors'
|
45
|
-
gem '
|
45
|
+
gem 'letter_opener_web'
|
46
46
|
gem 'listen'
|
47
47
|
gem 'spring'
|
48
48
|
gem 'spring-watcher-listen'
|
@@ -51,7 +51,6 @@ end
|
|
51
51
|
|
52
52
|
group :test do
|
53
53
|
gem 'capybara'
|
54
|
-
gem 'fuubar'
|
55
54
|
gem 'rspec-rails'
|
56
55
|
gem 'selenium-webdriver'
|
57
56
|
gem 'shoulda-matchers'
|
@@ -60,7 +59,6 @@ group :test do
|
|
60
59
|
end
|
61
60
|
|
62
61
|
group :development, :test do
|
63
|
-
gem 'awesome_print'
|
64
62
|
gem 'brakeman', require: false
|
65
63
|
gem 'bullet'
|
66
64
|
gem 'bundler-audit', require: false
|
@@ -69,7 +67,6 @@ group :development, :test do
|
|
69
67
|
gem 'ffaker'
|
70
68
|
gem 'i18n-tasks'
|
71
69
|
gem 'lol_dba'
|
72
|
-
gem 'pry-byebug'
|
73
70
|
gem 'pry-rails'
|
74
71
|
gem 'pry-rescue'
|
75
72
|
gem 'pry-stack_explorer'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Docker for development
|
2
|
+
|
3
|
+
## Provisioning
|
4
|
+
|
5
|
+
Install dependencies and create/migrate db schema with seeds
|
6
|
+
|
7
|
+
```
|
8
|
+
$ docker-compose run --rm runner
|
9
|
+
|
10
|
+
> bundle install
|
11
|
+
> yarn install
|
12
|
+
> rails db:create
|
13
|
+
> rails db:migrate
|
14
|
+
> rails data:migrate
|
15
|
+
```
|
16
|
+
|
17
|
+
## Run server
|
18
|
+
|
19
|
+
```
|
20
|
+
$ docker-compose run --rm --service-ports rails
|
21
|
+
```
|
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
default: &default
|
3
|
+
adapter: postgresql
|
4
|
+
encoding: unicode
|
5
|
+
pool: <%= ENV.fetch('RAILS_MAX_THREADS') { 5 } %>
|
6
|
+
|
7
|
+
development: &development
|
8
|
+
<<: *default
|
9
|
+
host: postgres
|
10
|
+
port: 5432
|
11
|
+
username: postgres
|
12
|
+
password: postgres
|
13
|
+
database: '<%= "#{app_name}_development" %>'
|
14
|
+
|
15
|
+
test:
|
16
|
+
<<: *development
|
17
|
+
database: '<%= "#{app_name}_test" %>'
|
18
|
+
|
19
|
+
production:
|
20
|
+
<<: *default
|
21
|
+
url: <%= ENV['DATABASE_URL'] %>
|