geb 0.1.11

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.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +3 -0
  3. data/CHANGELOG.md +37 -0
  4. data/CODE_OF_CONDUCT.md +84 -0
  5. data/LICENSE +21 -0
  6. data/README.md +384 -0
  7. data/Rakefile +21 -0
  8. data/bin/geb +21 -0
  9. data/lib/geb/cli.rb +40 -0
  10. data/lib/geb/commands/build.rb +59 -0
  11. data/lib/geb/commands/init.rb +70 -0
  12. data/lib/geb/commands/release.rb +54 -0
  13. data/lib/geb/commands/remote.rb +48 -0
  14. data/lib/geb/commands/server.rb +77 -0
  15. data/lib/geb/commands/upload.rb +48 -0
  16. data/lib/geb/commands/version.rb +36 -0
  17. data/lib/geb/config.rb +103 -0
  18. data/lib/geb/defaults.rb +44 -0
  19. data/lib/geb/git.rb +112 -0
  20. data/lib/geb/page.rb +217 -0
  21. data/lib/geb/partial.rb +150 -0
  22. data/lib/geb/samples/basic/assets/css/site.css +7 -0
  23. data/lib/geb/samples/basic/assets/images/android-chrome-192x192.png +0 -0
  24. data/lib/geb/samples/basic/assets/images/android-chrome-512x512.png +0 -0
  25. data/lib/geb/samples/basic/assets/images/apple-touch-icon.png +0 -0
  26. data/lib/geb/samples/basic/assets/images/favicon-16x16.png +0 -0
  27. data/lib/geb/samples/basic/assets/images/favicon-32x32.png +0 -0
  28. data/lib/geb/samples/basic/assets/images/favicon.ico +0 -0
  29. data/lib/geb/samples/basic/assets/images/hero.png +0 -0
  30. data/lib/geb/samples/basic/assets/images/og-thumb.png +0 -0
  31. data/lib/geb/samples/basic/assets/images/twitter-thumb.png +0 -0
  32. data/lib/geb/samples/basic/assets/js/site.js +5 -0
  33. data/lib/geb/samples/basic/geb.config.yml +70 -0
  34. data/lib/geb/samples/basic/index.html +11 -0
  35. data/lib/geb/samples/basic/page.html +11 -0
  36. data/lib/geb/samples/basic/shared/partials/_analytics.html +9 -0
  37. data/lib/geb/samples/basic/shared/partials/_footer.html +3 -0
  38. data/lib/geb/samples/basic/shared/partials/_global_assets.html +19 -0
  39. data/lib/geb/samples/basic/shared/partials/_header.html +0 -0
  40. data/lib/geb/samples/basic/shared/partials/_meta_tags.html +34 -0
  41. data/lib/geb/samples/basic/shared/templates/_blog_post.html +0 -0
  42. data/lib/geb/samples/basic/shared/templates/_site.html +19 -0
  43. data/lib/geb/samples/basic/site.webmanifest +1 -0
  44. data/lib/geb/samples/bootstrap_jquery/assets/css/site.css +7 -0
  45. data/lib/geb/samples/bootstrap_jquery/assets/images/android-chrome-192x192.png +0 -0
  46. data/lib/geb/samples/bootstrap_jquery/assets/images/android-chrome-512x512.png +0 -0
  47. data/lib/geb/samples/bootstrap_jquery/assets/images/apple-touch-icon.png +0 -0
  48. data/lib/geb/samples/bootstrap_jquery/assets/images/favicon-16x16.png +0 -0
  49. data/lib/geb/samples/bootstrap_jquery/assets/images/favicon-32x32.png +0 -0
  50. data/lib/geb/samples/bootstrap_jquery/assets/images/favicon.ico +0 -0
  51. data/lib/geb/samples/bootstrap_jquery/assets/images/hero.png +0 -0
  52. data/lib/geb/samples/bootstrap_jquery/assets/images/og-thumb.png +0 -0
  53. data/lib/geb/samples/bootstrap_jquery/assets/images/twitter-thumb.png +0 -0
  54. data/lib/geb/samples/bootstrap_jquery/assets/js/site.js +5 -0
  55. data/lib/geb/samples/bootstrap_jquery/blog/blog_post_1.html +35 -0
  56. data/lib/geb/samples/bootstrap_jquery/blog/blog_post_2.html +35 -0
  57. data/lib/geb/samples/bootstrap_jquery/blog/blog_post_3.html +35 -0
  58. data/lib/geb/samples/bootstrap_jquery/blog/index.html +17 -0
  59. data/lib/geb/samples/bootstrap_jquery/geb.config.yml +69 -0
  60. data/lib/geb/samples/bootstrap_jquery/index.html +11 -0
  61. data/lib/geb/samples/bootstrap_jquery/page.html +11 -0
  62. data/lib/geb/samples/bootstrap_jquery/shared/partials/_analytics.html +9 -0
  63. data/lib/geb/samples/bootstrap_jquery/shared/partials/_footer.html +3 -0
  64. data/lib/geb/samples/bootstrap_jquery/shared/partials/_global_assets.html +19 -0
  65. data/lib/geb/samples/bootstrap_jquery/shared/partials/_header.html +0 -0
  66. data/lib/geb/samples/bootstrap_jquery/shared/partials/_meta_tags.html +34 -0
  67. data/lib/geb/samples/bootstrap_jquery/shared/templates/_blog_post.html +0 -0
  68. data/lib/geb/samples/bootstrap_jquery/shared/templates/_site.html +19 -0
  69. data/lib/geb/samples/bootstrap_jquery/site.webmanifest +1 -0
  70. data/lib/geb/samples/geb.config.yml +70 -0
  71. data/lib/geb/server.rb +138 -0
  72. data/lib/geb/site/build.rb +189 -0
  73. data/lib/geb/site/core.rb +229 -0
  74. data/lib/geb/site/release.rb +70 -0
  75. data/lib/geb/site/remote.rb +142 -0
  76. data/lib/geb/site/template.rb +208 -0
  77. data/lib/geb/site.rb +83 -0
  78. data/lib/geb/template.rb +166 -0
  79. data/lib/geb/utilities.rb +110 -0
  80. data/lib/geb.rb +36 -0
  81. data/lib/seth.rb +50 -0
  82. data/sig/geb.rbs +4 -0
  83. data/test/api tests/test_cli.rb +200 -0
  84. data/test/api tests/test_config.rb +330 -0
  85. data/test/api tests/test_defaults.rb +62 -0
  86. data/test/api tests/test_git.rb +105 -0
  87. data/test/api tests/test_page.rb +320 -0
  88. data/test/api tests/test_partial.rb +152 -0
  89. data/test/api tests/test_server.rb +416 -0
  90. data/test/api tests/test_site.rb +1315 -0
  91. data/test/api tests/test_template.rb +249 -0
  92. data/test/api tests/test_utilities.rb +162 -0
  93. data/test/command tests/test_geb_build.rb +199 -0
  94. data/test/command tests/test_geb_init.rb +312 -0
  95. data/test/command tests/test_geb_release.rb +166 -0
  96. data/test/command tests/test_geb_remote.rb +66 -0
  97. data/test/command tests/test_geb_server.rb +122 -0
  98. data/test/command tests/test_geb_upload.rb +96 -0
  99. data/test/command tests/test_geb_version.rb +58 -0
  100. data/test/support/geb_api_test.rb +37 -0
  101. data/test/support/geb_cli_test.rb +275 -0
  102. data/test/support/geb_minitest_ext.rb +35 -0
  103. data/test/support/geb_test_helpers.rb +84 -0
  104. data/test/support/geb_web_server_proxy.rb +128 -0
  105. data/test/test_helper.rb +61 -0
  106. metadata +301 -0
data/lib/geb/page.rb ADDED
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Represents a site object, handles creation of new sites and site templates
4
+ # Templates can be one of the following:
5
+ # - name of the site template that comes bundled with geb
6
+ # - a local directory that is a valid site template
7
+ # - a URL to a geb site template packaged as a zip file
8
+ #
9
+ # @title Geb - Page
10
+ # @author Edin Mustajbegovic <edin@actiontwelve.com>
11
+ # @copyright 2024 Edin Mustajbegovic
12
+ # @license MIT
13
+ #
14
+ # @todo Make insert pattern configurable
15
+ #
16
+ # @see https://github.com/mainfram-work/geb for more information
17
+
18
+ # include the required libraries
19
+ require 'fileutils'
20
+
21
+ module Geb
22
+ class Page
23
+
24
+ # insert pattern constant
25
+ INSERT_PATTERN = /<%= insert: (.*?) %>/
26
+
27
+ class PageFileNotFound < Geb::Error
28
+ MESSAGE = "Page file not found".freeze
29
+ def initialize(e = ""); super(e, MESSAGE); end
30
+ end # class PageFileNotFound < Geb::Error
31
+
32
+ class PageFileReadFailure < Geb::Error
33
+ MESSAGE = "Failed to read the page file.".freeze
34
+ def initialize(e = ""); super(e, MESSAGE); end
35
+ end # class PageFileReadFailure < Geb::Error
36
+
37
+ class PageMissingTemplateDefition < Geb::Error
38
+ MESSAGE = "Page is missing template defitions but has insert sections defined".freeze
39
+ def initialize(e = ""); super(e, MESSAGE); end
40
+ end # class PageMissingTemplateDefition < Geb::Error
41
+
42
+ class FailedToOutputPage < Geb::Error
43
+ MESSAGE = "Failed to create output page".freeze
44
+ def initialize(e = ""); super(e, MESSAGE); end
45
+ end # class FailedToOutputPage < Geb::Error
46
+
47
+ # @!attribute [r] site
48
+ # @return [Geb::Site] the site object
49
+ attr_reader :site
50
+
51
+ # @!attribute [r] path
52
+ # @return [String] the page path
53
+ attr_reader :path
54
+
55
+ # @!attribute [r] content
56
+ # @return [String] the page content
57
+ attr_reader :content
58
+
59
+ # @!attribute [r] parsed_content
60
+ # @return [String] the parsed page content
61
+ attr_reader :parsed_content
62
+
63
+ # page constructor, initializes the page object and attributes
64
+ # @param site [Geb::Site] the site object
65
+ # @param path [String] the page path
66
+ # @raise [PageFileNotFound] if the page file does not exist
67
+ # @raise [PageFileReadFailure] if the page file could not be read
68
+ # @return [Geb::Page] the page object
69
+ def initialize(site, path)
70
+
71
+ # set the site and path
72
+ @site = site
73
+ @path = path
74
+
75
+ # check if the page file exists
76
+ raise PageFileNotFound.new(@path) unless page_file_exists?
77
+
78
+ Geb.log ""
79
+ Geb.log " - loading page: #{page_name}"
80
+
81
+ # read the page file, raise an error if the file could not be read
82
+ begin
83
+ @content = File.read(@path)
84
+ rescue => e
85
+ raise PageFileReadFailure.new(e.message)
86
+ end # begin
87
+
88
+ # parse the page content
89
+ parse()
90
+
91
+ end # def initialize
92
+
93
+ # parse the page content for templates and partials
94
+ def parse
95
+
96
+ # initalise the new page content
97
+ @parsed_content = @content.dup
98
+
99
+ # parse the content for templates and partials
100
+ @parsed_content = parse_for_templates(@parsed_content)
101
+ @parsed_content = parse_for_partials(@parsed_content)
102
+
103
+ end # def parse
104
+
105
+ # parse the content for templates. This method will keep looking for templates until all templates are found as
106
+ # templates can be based on templates.
107
+ # @param content [String] the content to parse for templates. Default is the parsed page content.
108
+ # @return [String] the parsed content, with no templates to parse.
109
+ # @raise [PageMissingTemplateDefition] if a template sections are found but the template declaration is not.
110
+ def parse_for_templates(content = @parsed_content)
111
+
112
+ # initialise a flag to keep looking for templates
113
+ keep_looking_for_template = true
114
+
115
+ # keep looking for template until we find them all
116
+ while keep_looking_for_template
117
+
118
+ # attempt to extract the template path and sections
119
+ template_path = Geb::Template.extract_template_path(content)
120
+ template_sections = Geb::Template.extract_sections_for_template(content)
121
+
122
+ # raise an error if template sections are defined but the template is not
123
+ raise PageMissingTemplateDefition.new(page_name) if template_sections.any? && template_path.nil?
124
+
125
+ # check if we found a template
126
+ if template_path.nil?
127
+
128
+ # we did not find a template, so we are done
129
+ keep_looking_for_template = false
130
+
131
+ else
132
+
133
+ # create a new template object
134
+ template = Geb::Template.load(File.join(@site.site_path, template_path))
135
+
136
+ # parse the template content and replace the insert sections
137
+ content = template.parse(template_sections)
138
+
139
+ end # unless template_path.nil?
140
+
141
+ end # while keep_looking_for_template
142
+
143
+ # return the parsed content with templates handled
144
+ return content
145
+
146
+ end # def parse_for_templates
147
+
148
+ # parse the content for partials. This method will keep looking for partials until all partials are found as
149
+ # partials can be embeded in other partials.
150
+ # @param content [String] the content to parse for partials. Default is the parsed page content.
151
+ # @return [String] the parsed content, with no partials to parse.
152
+ def parse_for_partials(content = @parsed_content)
153
+
154
+ # initialise a flag to keep looking for partials
155
+ keep_looking_for_partials = true
156
+
157
+ # keep looking for partials until we find them all (partials can be embeded in other partials)
158
+ while keep_looking_for_partials
159
+
160
+ # attempt to extract the partial paths
161
+ found_partials, content = Geb::Partial.process_partials(@site.site_path, content)
162
+
163
+ # check if we found any partials, if not we are done
164
+ keep_looking_for_partials = (found_partials != 0)
165
+
166
+ end # while keep_looking_for_partials
167
+
168
+ # return the parsed content with partials handled
169
+ return content
170
+
171
+ end # def parse_for_partials
172
+
173
+ # build the page, save it to the output folder
174
+ # @param output_path [String] the output path
175
+ # @raise [FailedToOutputPage] if the page could not be saved to the output folder
176
+ def build(output_path)
177
+
178
+ # build the page
179
+ Geb.log " - building page: #{page_name}"
180
+
181
+ # strip whitespace (spaces and newlines) at the beginning and at the end of the file
182
+ @parsed_content = @parsed_content.strip
183
+
184
+ # build the output filename
185
+ output_filename = @path.gsub(@site.site_path, output_path)
186
+
187
+ # attempt to create the output directory and file
188
+ begin
189
+
190
+ # make sure the output directory for the file exists
191
+ FileUtils.mkdir_p(File.dirname(output_filename))
192
+
193
+ # write the content to the output file
194
+ File.write(output_filename, @parsed_content)
195
+
196
+ rescue => e
197
+ raise FailedToOutputPage.new(e.message)
198
+ end # begin rescue
199
+
200
+ end # def build
201
+
202
+ private
203
+
204
+ # get the page name by removing the site folder from the path
205
+ # @return [String]
206
+ def page_name
207
+ return @path.gsub(@site.site_path, '')
208
+ end # def page_name
209
+
210
+ # check if the page file exists, returns true if the file exists, false otherwise
211
+ # @return [Boolean]
212
+ def page_file_exists?
213
+ return File.exist?(@path)
214
+ end # def page_file_exists?
215
+
216
+ end # class Page
217
+ end # module Geb
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Represents a page partial. A page partial is a file that contains
4
+ # content that is to be inserted in the page at the pace where the partial was
5
+ # declared. The class keeps a cache of already loaded partials.
6
+ #
7
+ # @title Geb - Partial
8
+ # @author Edin Mustajbegovic <edin@actiontwelve.com>
9
+ # @copyright 2024 Edin Mustajbegovic
10
+ # @license MIT
11
+ #
12
+ # @todo Make partial pattern configurable
13
+ #
14
+ # @see https://github.com/mainfram-work/geb for more information
15
+
16
+ # include the required libraries
17
+ require 'fileutils'
18
+
19
+ module Geb
20
+ class Partial
21
+
22
+ # partial pattern constant
23
+ PARTIAL_PATTERN = /<%= partial: (?<path>.*?) %>/
24
+
25
+ class PartialFileNotFound < Geb::Error
26
+ MESSAGE = "Partial file not found".freeze
27
+ def initialize(e = ""); super(e, MESSAGE); end
28
+ end # class PartialFileNotFound < Geb::Error
29
+
30
+ class PartialFileReadFailure < Geb::Error
31
+ MESSAGE = "PFailed to read the partial file.".freeze
32
+ def initialize(e = ""); super(e, MESSAGE); end
33
+ end # class PartialFileReadFailure < Geb::Error
34
+
35
+ # define a class level cache for loaded partial objects
36
+ @@loaded_partials = {}
37
+
38
+ # class method to expire the partial cache
39
+ def self.expire_cache
40
+ @@loaded_partials = {}
41
+ end # def self.expire_cache
42
+
43
+ # class method to initialise a partial if it is not already loaded, otherwise, return the cached partial
44
+ # @param partial_path [String] the path to the partial file
45
+ # @return [Geb::Partial] the partial object
46
+ def self.load(partial_path)
47
+
48
+ # initialise a return partial object
49
+ return_partial = nil
50
+
51
+ # check if the partial is already loaded
52
+ if @@loaded_partials.key?(partial_path)
53
+
54
+ # return the cached partial
55
+ Geb.log " - using cached partial: #{partial_path}"
56
+ return_partial = @@loaded_partials[partial_path]
57
+
58
+ else
59
+
60
+ # create a new partial object
61
+ return_partial = Partial.new(partial_path)
62
+
63
+ # add the partial to the cache
64
+ @@loaded_partials[partial_path] = return_partial
65
+
66
+ end # if else
67
+
68
+ # return the partial object
69
+ return return_partial
70
+
71
+ end # def self.load
72
+
73
+ # class method to process partials in a page
74
+ # @param site_path [String] the path to the site
75
+ # @param page_content [String] the content of the page
76
+ # @return [Array] an array containing the number of partials found and the page content
77
+ # @raise [PartialFileNotFound] if the partial file does not exist
78
+ # @raise [PartialFileReadFailure] if the partial file could not be read
79
+ def self.process_partials(site_path, page_content)
80
+
81
+ # initialise a counter to count the number of partials found on the page
82
+ partial_count = 0
83
+
84
+ # initialize return page content
85
+ return_page_content = page_content.dup
86
+
87
+ # scan the page content for partials
88
+ return_page_content.gsub!(PARTIAL_PATTERN) do |match|
89
+
90
+ # match the partial relative and full paths
91
+ partial_file_path = match.match(PARTIAL_PATTERN)[:path].strip
92
+ partial_file_full_path = File.join(site_path, partial_file_path)
93
+
94
+ # load the partial object
95
+ partial = Partial.load(partial_file_full_path)
96
+
97
+ # increment the partial count
98
+ partial_count += 1
99
+
100
+ # return the partial content
101
+ partial.content
102
+
103
+ end # page_content.scan(PARTIAL_PATTERN) do |match|
104
+
105
+ # return the array of partial paths
106
+ return partial_count, return_page_content
107
+
108
+ end # def self.extract_partial_paths
109
+
110
+ # @!attribute [r] path
111
+ # @return [String] the path to the partial file
112
+ attr_reader :path
113
+
114
+ # @!attribute [r] content
115
+ # @return [String] the content of the partial file
116
+ attr_reader :content
117
+
118
+ # initialise a new partial object
119
+ # @param partial_path [String] the path to the partial file
120
+ # @raise [PartialFileNotFound] if the partial file does not exist
121
+ # @raise [PartialFileReadFailure] if the partial file could not be read
122
+ # @return [Geb::Partial] the partial object
123
+ def initialize(partial_path)
124
+
125
+ # set the partial path
126
+ @path = partial_path
127
+ @content = nil
128
+
129
+ # check if the partial file exists
130
+ raise PartialFileNotFound.new(partial_path) unless partial_file_exists?()
131
+
132
+ Geb.log " - loading partial: #{@path}"
133
+
134
+ # read the template file, raise an error if the file could not be read
135
+ begin
136
+ @content = File.read(partial_path)
137
+ rescue => e
138
+ raise PartialFileReadFailure.new(e.message)
139
+ end # begin
140
+
141
+ end # def initialize
142
+
143
+ # check if the partial file exists
144
+ # @return [Boolean] true if the partial file exists, otherwise false
145
+ def partial_file_exists?
146
+ return File.exist?(@path)
147
+ end # def template_file_exists?
148
+
149
+ end # class Partial
150
+ end # module Geb
@@ -0,0 +1,7 @@
1
+ BODY {
2
+ background-color: #1A2D3D;
3
+ font-family: Arial, sans-serif;
4
+ margin: 0;
5
+ padding: 0;
6
+ color: #fff;
7
+ }
@@ -0,0 +1,5 @@
1
+
2
+ // use jquery to log a message to the console once the page loads
3
+ $(document).ready(function() {
4
+ console.log('site.js loaded');
5
+ }
@@ -0,0 +1,70 @@
1
+
2
+ # Geb Configuration File
3
+ # =======================
4
+ #
5
+ # This is a sample configuration file for the geb command line tool.
6
+ # You pretty much don't have to specify anything in this file, unless you want to
7
+ # customize the site. The default values are good enough for most sites.
8
+ #
9
+ # EVEN IF YOU DON"T SPECIFY ANYTHING IN THIS FILE, THIS CONFIG FILE MUST EXIST
10
+ # AT THE ROOT OF THE SITE DIRECTORY. OTHERWISE, THE GEB COMMANDS WILL NOT WORK.
11
+ # IT CAN BE EMPTY, BUT IT MUST EXIST. GEB DEMANDS IT.
12
+ #
13
+ # However, remote_uri and remote_path are required if you want to use
14
+ # the geb remote and upload commands. If you plan to upload the site on your own then
15
+ # you don't need to specify these values.
16
+ #
17
+
18
+ # Name of the site.
19
+ # If not specified, the default is the name of the directory where the site is located.
20
+ # Just for display purposes.
21
+ #site_name: "My Site"
22
+
23
+ # The remote_uri is the SSH URI of the remote server that you are deploying to.
24
+ # Geb remote and upload commands will use this URI to connect to the server.
25
+ # If you don't specify a remote_uri, geb remote and upload commands will not work.
26
+ # Typical format is username@server
27
+ #remote_uri: "user@server.com"
28
+
29
+ # The remote_path is the path on the remote server where the site is located.
30
+ # If you don't specify a remote_path, upload commands will not work.
31
+ #remote_path: "/path/to/site"
32
+
33
+ # Set the local web server port that the site will run on.
34
+ # Geb server command will use this port to start the local web server
35
+ # If you don't specify a port, geb server command auto selects a port
36
+ #local_port: 4000
37
+
38
+ # Specifies the output directory, this directory will be used to store the output of
39
+ # the build and release commands.
40
+ # the output directory is relative to the site directory.
41
+ # The default value is "output"
42
+ #output_dir: "output"
43
+
44
+ # Specifies the assets directory, this directory will be used to store the assets.
45
+ # The assets directory is relative to the site directory.
46
+ # The default value is "assets"
47
+ #assets_dir: "assets"
48
+
49
+ # Specifies the page extensions that are used in the site. This can be any text file extension.
50
+ # Default value is ['.md', '.markdown', '.html', '.htm', '.txt', '.js', '.css']
51
+ #page_extensions: ["html", "htm", "md", "markdown"]
52
+
53
+ # Template and partial identifier is a regular expression that is used to identify the template
54
+ # and partial files in the site. The default value is /^_/, any filename that starts with an underscore.
55
+ # These files are processed, but not included in the output directory, local or release.
56
+ # This setting does not impact template paths below, which are used to share the site as a template,
57
+ # which will include the template and partial files, if the template_paths includes them.
58
+ #template_and_partial_identifier: /^_/
59
+
60
+ # if you want to share the site as a template site, specify which files and directories
61
+ # are part of the template.
62
+ # When you create a new site, these files and directories will be copied to the new site
63
+ # If you don't specify template_paths, the site will not be shared as a template site and
64
+ # the geb release --with_template option will not work.
65
+ # Likewise, for other sites to use this site as a template, you must specify the template_paths.
66
+ # The site template files will be archived into geb-template.tar.gz file and put within
67
+ # the release directory.
68
+ # e.g. template_paths: ["assets", "shared", "*.html", "site.webmanifest"]
69
+ #template_paths: []
70
+
@@ -0,0 +1,11 @@
1
+ <% template: shared/templates/_site.html %>
2
+
3
+ <% start: title %>
4
+ This is a website title
5
+ <% end: title %>
6
+
7
+ <% start: content %>
8
+
9
+ <p>Welcome to the site</p>
10
+
11
+ <% end: content %>
@@ -0,0 +1,11 @@
1
+ <% template: shared/templates/_site.html %>
2
+
3
+ <% start: title %>
4
+ This is another page
5
+ <% end: title %>
6
+
7
+ <% start: content %>
8
+
9
+ <p>Welcome to the other page</p>
10
+
11
+ <% end: content %>
@@ -0,0 +1,9 @@
1
+
2
+ <!-- Global Site Tag (gtag-js) - Google Analytics -->
3
+ <script async src="https://www.googletagmanager.com/gtag/js?id=GA_TRACKING_ID"></script>
4
+ <script>
5
+ window.dataLayer = window.dataLayer || [];
6
+ function gtag() {databayer-push (arguments) ; }
7
+ gtag( 'js', new Date());
8
+ gtag( 'config', 'GA_TRACKING_ID' );
9
+ </script>
@@ -0,0 +1,3 @@
1
+
2
+ <!-- Bootstrap Bundle -->
3
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
@@ -0,0 +1,19 @@
1
+ <!-- Bootstrap icons-->
2
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" >
3
+
4
+ <!-- Bootstrap CSS -->
5
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
6
+
7
+ <!-- Custom CSS styles -->
8
+ <link href="_{site_url}_/assets/css/site.css" rel="stylesheet" />
9
+
10
+ <!--
11
+ The Bootstrap JavaScript bundle is not here, but is included in the footer of the page.
12
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
13
+ -->
14
+
15
+ <!-- jQuery -->
16
+ <script src="https://code.jquery.com/jquery-3.7.1.slim.min.js" integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8=" crossorigin="anonymous"></script>
17
+
18
+ <!-- Custom Javascript -->
19
+ <script src="_{site_url}_/assets/js/site.js"></script>
@@ -0,0 +1,34 @@
1
+
2
+ <!-- Meta tags -->
3
+ <meta charset="utf-8" />
4
+ <meta name="generator" content="Geb 1.0.0" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
6
+ <meta name=”robots” content="index, follow" />
7
+ <meta name="description" content="_{title}_" />
8
+ <meta name="keywords" content="geb,geb static site,static site" />
9
+ <meta name="author" content="Geb, the Egyptian god of earth" />
10
+
11
+ <!-- Favicon and site icon -->
12
+ <link rel="apple-touch-icon" type="image/png" sizes="180x180" href="_{site_url}_/assets/images/apple-touch-icon.png" />
13
+ <link rel="icon" type="image/png" sizes="32x32" href="_{site_url}_/assets/images/favicon-32x32.png" />
14
+ <link rel="icon" type="image/png" sizes="16x16" href="_{site_url}_/assets/images/favicon-16x16.png" />
15
+ <link rel="icon" type="image/x-icon" href="_{site_url}_/assets/images/favicon.ico" />
16
+ <link rel="shortcut icon" type="image/x-icon" href="_{site_url}_/assets/images/favicon.ico" />
17
+
18
+ <!-- Site manifest -->
19
+ <link rel="canonical" href="_{site_url}_/_{relative_path}_" />
20
+ <link rel="manifest" type="image/png" href="/site.webmanifest" />
21
+
22
+ <!-- Open Graph -->
23
+ <meta property="og:type" content="website" />
24
+ <meta property="og:title" content="_{title}_" />
25
+ <meta property="og:description" content="_{title}_." />
26
+ <meta property="og:image" content="_{site_url}_/assets/images/og-thumb.png" />
27
+
28
+ <!-- Twitter Cards -->
29
+ <meta name="twitter:card" content="summary_large_image" />
30
+ <meta name="twitter:site" content="@twitter" />
31
+ <meta name="twitter:title" content="_{title}_" />
32
+ <meta name="twitter:description" content="_{title}_" />
33
+ <meta name="twitter:image" content="_{site_url}_/assets/images/twitter-thumb.png" />
34
+
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+
5
+ <title><%= insert: title %></title>
6
+
7
+ <%= partial: shared/partials/_analytics.html %>
8
+ <%= partial: shared/partials/_meta_tags.html %>
9
+ <%= partial: shared/partials/_global_assets.html %>
10
+
11
+ </head>
12
+ <body>
13
+
14
+ <%= partial: shared/partials/_header.html %>
15
+ <%= insert: content %>
16
+ <%= partial: shared/partials/_footer.html %>
17
+
18
+ </body>
19
+ </html>
@@ -0,0 +1 @@
1
+ {"name":"","short_name":"","icons":[{"src":"/assets/images/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/assets/images/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
@@ -0,0 +1,7 @@
1
+ BODY {
2
+ background-color: #1A2D3D;
3
+ font-family: Arial, sans-serif;
4
+ margin: 0;
5
+ padding: 0;
6
+ color: #fff;
7
+ }
@@ -0,0 +1,5 @@
1
+
2
+ // use jquery to log a message to the console once the page loads
3
+ $(document).ready(function() {
4
+ console.log('site.js loaded');
5
+ }