geb 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
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
+ }