shoreditch 1.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2afe1ffff65e9ece59afc75378470a72fcafc495f74d1a9b3f25396c03452a70
4
+ data.tar.gz: 6990c1918011c9a5b60660e737e438964a52fe511180bbdbf0bc59ca30f50f21
5
+ SHA512:
6
+ metadata.gz: 6a3f2dbac7af5e77dc3b06a55c79edca5b630201bee92d74240ae4a4f87522dcfafc1571f606ba765b1d532197dfb695f0dd93b2fabe2d0c5650efb5cd1130ca
7
+ data.tar.gz: 7e848819d28f74639dc9732f0f9211402ce4400c7f4d64c23b635392b48107fdf33c2bc954dbe798dbbe6ae0c2be4d30ee4428d9fb7f1fa72ddd8cbf8ad5cff9
data/CHANGELOG.md ADDED
@@ -0,0 +1,148 @@
1
+ # Changelog
2
+
3
+ ## 1.1.0
4
+
5
+ First version published to RubyGems. Restores features the 1.0.0 rewrite
6
+ dropped without recording, and fixes a set of defects that only showed up once
7
+ the demo rendered the theme correctly.
8
+
9
+ ### Fixed
10
+
11
+ - **The `accent` option did nothing.** `--sd-accent` was hardcoded in the
12
+ stylesheet and the configured value was never emitted. It is now applied from
13
+ the initializer, after the theme's CSS and before the site's own, and
14
+ validated so a site's config cannot inject CSS.
15
+ - **Index listings reserved a thumbnail column whether or not there was a
16
+ thumbnail**, squeezing every title and excerpt of a post without one into a
17
+ 128px ribbon.
18
+ - **Syntax highlighting is now owned by the theme.** It sets the code
19
+ background, so a site shipping the light-only Rouge palette that
20
+ `bridgetown new` generates rendered keywords black on near-black in dark
21
+ mode.
22
+ - `aria-current` was HTML-escaped, so the current nav item was never
23
+ highlighted.
24
+ - `<body>` carried `HashWithDotAccess::Hash`, from `data.class` resolving to
25
+ Ruby's `Object#class` rather than the front-matter `class` key.
26
+ - Excerpts were the first *source line*, so hard-wrapped markdown was cut
27
+ mid-sentence. `<!--more-->` is honoured, otherwise the first paragraph.
28
+ - Every generated tag page shared one `<title>`.
29
+ - Code blocks were padded twice, Rouge nesting `pre.highlight` inside
30
+ `div.highlight` and both matching the same rule.
31
+ - Pagination rendered an empty nav, and its margin, when there was one page.
32
+ - **An automation-installed site never rendered as the theme.** The scaffold's
33
+ starter layouts beat the theme's for every page whose front matter named
34
+ them — including the scaffold's own welcome post, whose explicit `layout:
35
+ post` also defeated the automation's `_defaults.yml` — and the starter
36
+ stylesheet trampled what remained. The automation now retires a starter
37
+ layout or stylesheet only when it is *exactly* the untouched scaffold
38
+ (whitespace aside), points the pages that named a retired layout at the
39
+ theme's — editing only their front matter, never a `layout:` line in body
40
+ text — and leaves anything a site has changed in place with a note.
41
+ - **The automation could execute a prompt answer as code.** Answers were
42
+ interpolated into the generated `config/initializers.rb` verbatim, so an
43
+ answer such as `#{`…`}` ran as Ruby every time the site loaded, and one
44
+ containing a quote produced a file that would not parse. Answers carrying a
45
+ quote, a backslash, a newline or a Ruby interpolation are now rejected with
46
+ a note to set that option by hand — escaping was not enough, because
47
+ Bridgetown's initializer insertion rewrites backslashes.
48
+
49
+ ### Added
50
+
51
+ - `--sd-rule-strong`, a heavier companion to `--sd-rule`. A hairline separator
52
+ can afford to be almost invisible; a border drawn around something so it reads
53
+ as one object cannot. Index entries use it.
54
+ - **Comments**, off unless configured. Giscus ships as the default provider;
55
+ overriding `components/shoreditch/comments.erb` swaps in any other. Replaces
56
+ the Disqus support removed in 1.0.0, without the third-party trackers.
57
+ - **The contact panel**, restored from the Jekyll `details.html` include. Brand
58
+ marks are vendored from Simple Icons (CC0) and inlined, rather than loading a
59
+ Font Awesome kit from a CDN on every page.
60
+ - **Per-page sidebar overrides** — `include_sticky`, `include_details`,
61
+ `include_logo`, `logo_location`, `logo_shape`, `logo_legend_shape` and
62
+ `flashy_logo`, as the Jekyll version had them.
63
+ - **CV styling**, opted into with `class: cv`. Not a layout: a CV is an
64
+ ordinary page whose front matter reshapes the sidebar and whose body class
65
+ tightens the type.
66
+ - `.pullquote` and `.code-title` styling, both of which the documentation
67
+ demonstrated but the stylesheet never defined.
68
+ - `.sd-archive` styling for a flat post archive — titles left, dates right in
69
+ tabular figures, a hairline rule between entries. The page supplies the
70
+ markup (the demo's Posts page groups by year); the theme ships the style.
71
+
72
+ ### Changed
73
+
74
+ - **The sidebar becomes a compact header band on narrow screens.** Below 60rem
75
+ it had been the desktop column rendered at phone width with nothing resized —
76
+ a 128px logo, a centred stack, the theme toggle and the copyright all ahead of
77
+ the article. On a 390px phone that was 439px of chrome, putting a post's title
78
+ at 80% of the first screen and its copyright notice above the headline. The
79
+ logo now sits inline with the site title, the navigation runs beneath it, and
80
+ the toggle and copyright drop to the foot of the page: 137px, with the title
81
+ at 45%. No menu to open and no JavaScript — the parts are promoted to items of
82
+ the page shell with `display: contents` and reordered.
83
+ - **Index entries are framed again**, as they were up to 0.9.0, rather than
84
+ separated by a hairline rule. The frame is what gives the listing a single
85
+ left edge: a post with no thumbnail began its title at the content edge while
86
+ its neighbours began an image-column in, so the stack read as ragged.
87
+ Thumbnails now sit flush to the frame and fill the card's height instead of
88
+ floating inside it with their own rounded corners, excerpts are clamped to
89
+ three lines at a line boundary, and the date moves above the title, set in the
90
+ mono face.
91
+ - **Index excerpts are set as plain text** whatever block the post opens with.
92
+ A post beginning with `{:.message}` or a blockquote put a filled, accent-barred
93
+ box in the listing while its neighbours stayed plain.
94
+ - **The sidebar splits top and bottom.** The logo, badge, site title and
95
+ tagline stay at the top of the column; the navigation and footer drop to the
96
+ bottom. Previously everything stacked from the top, leaving the empty space
97
+ below the nav with nothing to do.
98
+ - **Node 22 is now required** for the frontend build. Bridgetown's esbuild
99
+ configuration calls `fs.globSync`, added in Node 22; on Node 20 the build
100
+ fails while the site still serves, so CSS changes silently never appear.
101
+ Pinned in `demo/.nvmrc`.
102
+
103
+ ## 1.0.0
104
+
105
+ First Bridgetown release. Shoreditch was a Jekyll theme up to 0.9.0; this is a
106
+ rewrite rather than a port, so nothing upgrades in place from the Jekyll
107
+ version.
108
+
109
+ ### Changed
110
+
111
+ - Distributed as a gem-based Bridgetown plugin. Previously the only way to use
112
+ it was to clone or fork the repo and edit in place; now `bundle add
113
+ shoreditch` and `init :shoreditch` is enough, and updates arrive through
114
+ `bundle update`.
115
+ - Templates are ERB rather than Liquid, as components and layouts served
116
+ through a source manifest.
117
+ - Stylesheet rewritten. The inherited `hyde.sass` and `poole.sass` layers are
118
+ gone, along with the Sass dependency; it is now one plain CSS file driven by
119
+ custom properties.
120
+ - The sidebar is flexbox, finishing the rewrite announced but abandoned in the
121
+ Jekyll version's final week.
122
+ - Fonts are the system stack. The Jekyll version loaded Roboto and Rosario from
123
+ Google Fonts over plain HTTP, which was both a privacy leak and mixed
124
+ content.
125
+ - Favicon links are emitted only for files that exist. The Jekyll version
126
+ hard-coded seventeen icon links whether or not the site had them.
127
+
128
+ ### Added
129
+
130
+ - Light and dark themes, from `prefers-color-scheme` plus a sidebar toggle that
131
+ remembers the reader's choice. Applied before first paint, so no flash.
132
+ - Configuration through the initializer: `accent`, `sidebar_side`,
133
+ `logo_legend`, `logo_shape`.
134
+ - `bridgetown.automation.rb`, so `bin/bridgetown apply` installs and configures
135
+ the theme in one step.
136
+ - Open Graph and Twitter card metadata.
137
+ - A skip link, `aria-current` on the active nav item, and visible focus rings.
138
+ - `prefers-reduced-motion` support.
139
+
140
+ ### Removed
141
+
142
+ - Disqus comments. Add them from your own layout override if you want them.
143
+ - The Google Analytics hook. Use a privacy-preserving analytics script from
144
+ your site's own head if you need it.
145
+ - The `jekyll-paginate-v2` and `classifier-reborn` dependencies — Bridgetown
146
+ paginates natively, and related-posts is a site concern rather than a theme
147
+ one.
148
+ - The version badge in the sidebar.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ # Released under MIT License
2
+
3
+ Copyright (c) 2013 Mark Otto.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # Shoreditch
2
+
3
+ A two-column [Bridgetown](https://www.bridgetownrb.com) theme built for
4
+ technical blogging: a fixed sidebar, optional cover images, and a content
5
+ column deliberately wide enough that 80-character code samples do not wrap.
6
+
7
+ See it at [shoreditch.mehcoleman.com](https://shoreditch.mehcoleman.com).
8
+
9
+ Shoreditch is adapted from the excellent [Hyde](http://hyde.getpoole.com) theme
10
+ by [@mdo](https://github.com/mdo), and was also inspired by [Flexible
11
+ Jekyll](https://github.com/artemsheludko/flexible-jekyll) by Artem Sheludko.
12
+ Both are worth a look.
13
+
14
+ ## Install
15
+
16
+ ```
17
+ bin/bridgetown apply https://github.com/MEHColeman/shoreditch
18
+ ```
19
+
20
+ The automation asks for an accent colour and a badge text, installs the gem,
21
+ and points your posts and pages at the theme's layouts. On a fresh site it
22
+ also retires the scaffold's starter stylesheet and layouts, which would
23
+ otherwise override the theme — but only files that are *exactly* the untouched
24
+ `bridgetown new` scaffold; anything you have edited is left alone with a note.
25
+ An accent or badge answer that contains a quote, a backslash or a `#{…}` is
26
+ declined rather than written into your config, since it would otherwise land
27
+ in generated Ruby — set those options by hand if you need such characters.
28
+
29
+ Or by hand:
30
+
31
+ ```
32
+ bundle add shoreditch
33
+ ```
34
+
35
+ then in `config/initializers.rb`:
36
+
37
+ ```ruby
38
+ init :shoreditch
39
+ ```
40
+
41
+ There is nothing to add to your esbuild entry points. The theme's stylesheet
42
+ and script ship as static files through the gem's source manifest, so
43
+ `bundle update shoreditch` is all it takes to move to a new version.
44
+
45
+ ## Options
46
+
47
+ ```ruby
48
+ init :shoreditch do
49
+ accent "#c7254e" # any CSS colour; drives links, tags, focus rings
50
+ sidebar_side "right" # "left" (default) or "right"
51
+ logo_legend "For hire" # badge under the logo; omit for none
52
+ logo_shape "square" # "round" (default) or "square"
53
+ logo_legend_shape "straight" # "round" (default) or "straight"
54
+ end
55
+ ```
56
+
57
+ `accent` is validated before it reaches the stylesheet — a value that is not a
58
+ recognisable CSS colour falls back to the default rather than emitting broken
59
+ CSS.
60
+
61
+ ## Comments
62
+
63
+ Off unless configured. The theme ships [Giscus](https://giscus.app), which
64
+ stores comments as GitHub Discussions:
65
+
66
+ ```ruby
67
+ init :shoreditch do
68
+ comments({
69
+ repo: "you/your-repo", repo_id: "R_...",
70
+ category: "Comments", category_id: "DIC_...",
71
+ })
72
+ end
73
+ ```
74
+
75
+ The four values come from giscus.app once Discussions is enabled on the
76
+ repository. A single post opts out with `comments: false` in its front matter.
77
+
78
+ For any other provider, override `components/shoreditch/comments.erb` in your
79
+ own site — your files take precedence over the gem's, so there is no need to
80
+ fork the theme or copy the post layout. The thread follows the reader's theme
81
+ toggle, not just their OS setting.
82
+
83
+ ## Site metadata
84
+
85
+ In `src/_data/site_metadata.yml`:
86
+
87
+ ```yaml
88
+ title: Your Site
89
+ tagline: Shown under the title in the sidebar
90
+ description: Used for meta description and the feed
91
+ logo: /images/you.png
92
+ logo_link: /about/
93
+ author:
94
+ name: Your Name
95
+
96
+ # All optional, and all used only by the contact panel — see below.
97
+ github: yourhandle
98
+ mastodon: https://example.social/@you # a full URL, unlike the others
99
+ linkedin: yourhandle
100
+ twitter: yourhandle
101
+ instagram: yourhandle
102
+ reddit: yourhandle
103
+ youtube: https://youtube.com/@you # a full URL
104
+ tiktok: yourhandle
105
+ lastfm: yourhandle
106
+ deviantart: yourhandle
107
+ artstation: yourhandle
108
+ phone: "+44 20 7946 0000"
109
+ file_url: /files/cv.pdf
110
+ file_link_text: Download as PDF
111
+
112
+ # Split in two on purpose. The halves are only joined in the browser, so the
113
+ # address never appears whole in the HTML for a crawler to lift.
114
+ email_1: hello@examp
115
+ email_2: le.com
116
+ ```
117
+
118
+ ## The contact panel
119
+
120
+ A page opts in with `include_details: true`. It lists whichever of the author
121
+ fields above are filled in, with an inline icon each — brand marks are vendored
122
+ from [Simple Icons](https://simpleicons.org) (CC0), so the theme still loads
123
+ nothing from a third party.
124
+
125
+ It is off by default because a blog post has no use for a phone number; a CV or
126
+ an about page does.
127
+
128
+ ## Layouts
129
+
130
+ | Layout | Use |
131
+ | --- | --- |
132
+ | `shoreditch/default` | Wraps everything. Index pages use it directly. |
133
+ | `shoreditch/post` | Posts. Adds dates, tags, related posts and image credits. |
134
+ | `shoreditch/page` | Standalone pages. |
135
+
136
+ ## Front matter
137
+
138
+ | Key | Effect |
139
+ | --- | --- |
140
+ | `cover` | Full-width image above the content |
141
+ | `thumbnail` | Image in index listings |
142
+ | `last_updated` | Shown in the post header |
143
+ | `last_verified` | Shown in the post header — for saying how stale a technical post may be |
144
+ | `credits` | List of `label` / `name` / `via` / `via_link` for image attribution |
145
+ | `nav_order` | Puts a page in the sidebar nav, in this order |
146
+ | `exclude` | Keeps a page out of the sidebar nav |
147
+ | `noindex` | Emits `robots: noindex, nofollow` |
148
+ | `class` | Extra CSS class on `<body>` — `class: cv` opts into the CV styling |
149
+ | `comments` | `false` turns comments off for one post |
150
+
151
+ These reshape the sidebar for a single page — useful when one page should
152
+ introduce a person rather than the site:
153
+
154
+ | Key | Effect |
155
+ | --- | --- |
156
+ | `include_sticky` | `false` drops the site title, tagline and navigation |
157
+ | `include_details` | `true` shows the contact panel |
158
+ | `include_logo` | `false` hides the logo entirely |
159
+ | `logo_location` | A different logo image for this page |
160
+ | `logo_shape` | `round` or `square`, overriding the site setting |
161
+ | `logo_legend` | Overrides the badge; `false` hides it |
162
+ | `logo_legend_shape` | `round` or `straight` — the badge, shaped independently |
163
+ | `flashy_logo` | `true` gives the logo a pulsing accent glow |
164
+
165
+ ## Customising
166
+
167
+ Every colour and dimension is a custom property on `:root`, and your site's own
168
+ stylesheet loads after the theme's. To restyle, override what you need:
169
+
170
+ ```css
171
+ :root {
172
+ --sd-accent: rebeccapurple;
173
+ --sd-measure: 52rem;
174
+ --sd-sidebar-width: 20rem;
175
+ }
176
+ ```
177
+
178
+ Syntax highlighting is one of those properties. The theme sets the code
179
+ background, so it also sets the token colours — otherwise a light-only Rouge
180
+ palette renders keywords black on near-black as soon as dark mode flips the
181
+ background. Override `--sd-code-keyword`, `--sd-code-string`,
182
+ `--sd-code-comment`, `--sd-code-number`, `--sd-code-fn`, `--sd-code-tag` and
183
+ `--sd-code-punct` to use your own.
184
+
185
+ Rules come in two weights. `--sd-rule` is the hairline used for separators and
186
+ table borders; `--sd-rule-strong` is the heavier one used where a border encloses
187
+ something that has to read as a single object, as an index entry does. Override
188
+ them together if you are changing the palette.
189
+
190
+ Do not style `body`, `main` or bare `a` from your site's stylesheet — those
191
+ belong to the theme, and because your CSS loads last you will win by accident.
192
+ Override custom properties instead.
193
+
194
+ Light and dark both come from `prefers-color-scheme`, with a toggle in the
195
+ sidebar that stores the reader's choice and wins over the OS setting. The
196
+ choice is applied by an inline script before first paint, so there is no flash
197
+ of the wrong scheme.
198
+
199
+ Below 60rem the two columns stack, and the sidebar becomes a compact header
200
+ band: the logo shrinks and sits inline with the site title, the navigation runs
201
+ along under it, and the theme toggle and copyright move to the foot of the page
202
+ so a reader arriving on a post meets the masthead rather than the small print.
203
+ There is no menu to open — everything stays on screen, and no JavaScript is
204
+ involved.
205
+
206
+ The markdown classes the Jekyll version defined — `.message`, `.callout`,
207
+ `.alert`, `.alarm` — still work, so posts carrying them keep rendering.
208
+
209
+ ## Development
210
+
211
+ The `demo/` directory is a Bridgetown site that uses the theme from the parent
212
+ directory. It is what gets published to
213
+ [shoreditch.mehcoleman.com](https://shoreditch.mehcoleman.com), and it is the
214
+ quickest way to see a change:
215
+
216
+ ```
217
+ cd demo
218
+ bundle install
219
+ bin/bridgetown start
220
+ ```
221
+
222
+ Ruby 3.3+ and **Node 22 or newer** — Bridgetown's esbuild configuration calls
223
+ `fs.globSync`, which does not exist before Node 22. On an older Node the
224
+ frontend build fails while the site itself still serves, so stylesheet changes
225
+ silently never reach the browser. `demo/.nvmrc` pins it.
226
+
227
+ ## Licence
228
+
229
+ MIT. See [LICENSE.md](LICENSE.md) — the original copyright is Mark Otto's and
230
+ stays.
@@ -0,0 +1,277 @@
1
+ # Installs Shoreditch into an existing Bridgetown site.
2
+ #
3
+ # bin/bridgetown apply https://github.com/MEHColeman/shoreditch
4
+ #
5
+ # The theme's stylesheet and script ship as static files through the gem's
6
+ # source manifest, so there is nothing to add to esbuild entry points and no
7
+ # NPM package to install.
8
+ #
9
+ # This can run against a site with real content, so every destructive step is
10
+ # gated on the file being *exactly* the untouched `bridgetown new` scaffold
11
+ # (whitespace aside). Anything a site has edited is left alone with a note.
12
+ # The gate is deliberately strict: a newer Bridgetown scaffold this does not
13
+ # recognise is treated as "not ours to touch", so the automation degrades to
14
+ # advice rather than deleting someone's work.
15
+
16
+ add_gem "shoreditch"
17
+
18
+ # Both answers are written into the generated initializer as Ruby string
19
+ # literals (`accent "…"`). Reject any answer that could break out of the
20
+ # literal or smuggle interpolation (`#{…}`, `#@…`, `#$…`) rather than trying
21
+ # to escape it: Bridgetown's initializer insertion rewrites backslashes, so an
22
+ # escaped answer can be un-escaped on its way into the file — but an answer
23
+ # carrying none of these characters needs no escaping and cannot be reactived.
24
+ # A colour and a short badge never need them; anything that does is set by hand.
25
+ unsafe = ->(text) { text.match?(/["\\\r\n]|#[{@$]/) }
26
+
27
+ accent = ask("Accent colour (hex, blank for the default slate blue)?").to_s.strip
28
+ if unsafe.call(accent)
29
+ say "Ignoring the accent — it contained characters not allowed in a colour. " \
30
+ "Set `accent` by hand in config/initializers.rb.", :yellow
31
+ accent = ""
32
+ end
33
+
34
+ legend = ask("Badge text under the logo (blank for none)?").to_s.strip
35
+ if unsafe.call(legend)
36
+ say "Ignoring the badge text — it contained characters that aren't allowed. " \
37
+ "Set `logo_legend` by hand in config/initializers.rb.", :yellow
38
+ legend = ""
39
+ end
40
+
41
+ add_initializer :shoreditch do
42
+ settings = []
43
+ settings << %(accent "#{accent}") unless accent.empty?
44
+ settings << %(logo_legend "#{legend}") unless legend.empty?
45
+
46
+ if settings.empty?
47
+ ""
48
+ else
49
+ <<~RUBY
50
+ do
51
+ #{settings.join("\n ")}
52
+ end
53
+ RUBY
54
+ end
55
+ end
56
+
57
+ # Collapse whitespace so indentation and line-ending differences do not read
58
+ # as edits; any real change to the content does.
59
+ normalise = ->(text) { text.gsub(/\s+/, " ").strip }
60
+
61
+ pristine_default = <<~'ERB'
62
+ <!doctype html>
63
+ <html lang="<%= site.locale %>">
64
+ <head>
65
+ <%= render "head", metadata: site.metadata, title: data.title %>
66
+ </head>
67
+ <body class="<%= data.layout %> <%= data.page_class %>">
68
+ <%= render Shared::Navbar.new(metadata: site.metadata, resource: resource) %>
69
+
70
+ <main>
71
+ <%= yield %>
72
+ </main>
73
+
74
+ <%= render "footer", metadata: site.metadata %>
75
+ </body>
76
+ </html>
77
+ ERB
78
+
79
+ # `bridgetown new` generates page.erb and post.erb identically.
80
+ pristine_page_post = <<~'ERB'
81
+ ---
82
+ layout: default
83
+ ---
84
+
85
+ <h1><%= data.title %></h1>
86
+
87
+ <%= yield %>
88
+ ERB
89
+
90
+ pristine_css = <<~'CSS'
91
+ :root {
92
+ --body-background: #f2f2f2;
93
+ --body-color: #444;
94
+ --heading-color: black;
95
+ --action-color: #d64045;
96
+ }
97
+
98
+ body {
99
+ background: var(--body-background);
100
+ color: var(--body-color);
101
+ font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen",
102
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
103
+ "Helvetica", "Arial", sans-serif;
104
+ margin: 0 8px;
105
+ font-size: 108%;
106
+ line-height: 1.5;
107
+ }
108
+
109
+ a {
110
+ color: var(--action-color);
111
+ text-decoration: underline;
112
+ text-decoration-color: #ffb088;
113
+ }
114
+
115
+ h1 {
116
+ margin: 1rem 0 3rem;
117
+ text-align: center;
118
+ font-weight: 900;
119
+ font-size: 2.5rem;
120
+ color: var(--heading-color);
121
+ line-height: 1.2;
122
+ }
123
+
124
+ body > header {
125
+ margin: 1rem;
126
+ text-align: center;
127
+ }
128
+
129
+ body > header img {
130
+ display: inline-block;
131
+ width: 400px;
132
+ max-width: 100%;
133
+ }
134
+
135
+ body > nav ul {
136
+ margin: 2rem 0;
137
+ padding: 0;
138
+ list-style-type: none;
139
+ display: flex;
140
+ justify-content: center;
141
+ gap: 1.5rem;
142
+ font-size: 1.3rem;
143
+ font-weight: bold;
144
+ }
145
+
146
+ body > nav a {
147
+ text-decoration: none;
148
+ }
149
+
150
+ main {
151
+ margin: 2rem auto 4rem;
152
+ max-width: 65rem;
153
+ min-height: calc(100vh - 200px);
154
+ padding: 25px 25px 50px;
155
+ background: white;
156
+ box-shadow: 2px 3px 3px #ddd;
157
+ border-radius: 3px;
158
+
159
+ @media (max-width: 500px) {
160
+ padding: 16px 16px 50px;
161
+ }
162
+ }
163
+
164
+ footer {
165
+ text-align: center;
166
+ margin-bottom: 4rem;
167
+ font-size: 1em;
168
+ }
169
+
170
+ hr {
171
+ border: none;
172
+ border-top: 2px dotted #bbb;
173
+ margin: 3rem 0;
174
+ }
175
+ CSS
176
+
177
+ # The starter stylesheet styles body and main directly, and a site's own CSS
178
+ # loads after the theme's — so left in place it pulls the theme apart (it once
179
+ # cost the demo its entire appearance). Replace it only when it is exactly the
180
+ # untouched starter.
181
+ starter_css = "frontend/styles/index.css"
182
+ if File.exist?(starter_css)
183
+ if normalise.call(File.read(starter_css)) == normalise.call(pristine_css)
184
+ say "Clearing the starter stylesheet — its body/main rules override the theme…", :green
185
+ create_file starter_css, <<~CSS, force: true
186
+ /* Your site's styles load after the theme's, so anything here overrides
187
+ Shoreditch. Prefer overriding the theme's custom properties (see the
188
+ README) to styling body, main, or bare a directly. */
189
+ CSS
190
+ else
191
+ say "Left frontend/styles/index.css alone — it differs from the starter. " \
192
+ "Your CSS loads after the theme's, so remove any rules on body, main " \
193
+ "or bare a that fight it.", :yellow
194
+ end
195
+ end
196
+
197
+ say "Pointing your layouts at the theme…", :green
198
+
199
+ # The scaffold's own layouts beat the theme's for every page whose front
200
+ # matter names them — including the scaffold's welcome post — so a fresh site
201
+ # would not render as the theme anywhere. Retire each starter layout only when
202
+ # it is exactly the untouched scaffold; an edited layout is the site's own and
203
+ # stays, with a note.
204
+ layouts = {
205
+ "default" => [pristine_default, "shoreditch/default"],
206
+ "page" => [pristine_page_post, "shoreditch/page"],
207
+ "post" => [pristine_page_post, "shoreditch/post"],
208
+ }
209
+
210
+ retired = {}
211
+ layouts.each do |name, (pristine, replacement)|
212
+ file = "src/_layouts/#{name}.erb"
213
+ next unless File.exist?(file)
214
+
215
+ if normalise.call(File.read(file)) == normalise.call(pristine)
216
+ remove_file file
217
+ retired[name] = replacement
218
+ else
219
+ say "Left src/_layouts/#{name}.erb alone — it differs from the starter. " \
220
+ "Point pages that use it at #{replacement} yourself.", :yellow
221
+ end
222
+ end
223
+
224
+ # Repoint the pages that named a retired layout — but only inside the leading
225
+ # `---`…`---` front matter, so a `layout:` line in a post's body or a fenced
226
+ # code block is never touched, and tolerant of quoted values (layout: "post").
227
+ unless retired.empty?
228
+ Dir.glob("src/**/*.{md,markdown,erb,serb,liquid,html}").each do |page|
229
+ next unless File.file?(page)
230
+
231
+ text = File.read(page)
232
+ # A non-UTF-8 source would raise on the match below, aborting mid-way with
233
+ # layouts already removed; skip it so the pass is all-or-nothing.
234
+ next unless text.valid_encoding?
235
+ next unless text =~ /\A(---[ \t]*\r?\n)(.*?\r?\n)(---[ \t]*\r?\n)(.*)\z/m
236
+
237
+ open_fence, front, close_fence, body = $1, $2, $3, $4
238
+ changed = false
239
+ retired.each do |name, replacement|
240
+ # The `\r?` before the anchor keeps CRLF front matter matching, and the
241
+ # captured trailing group is re-emitted so the line ending is preserved.
242
+ front = front.sub(/^(layout:[ \t]*)["']?#{Regexp.escape(name)}["']?([ \t]*\r?)$/) do
243
+ changed = true
244
+ "#{$1}#{replacement}#{$2}"
245
+ end
246
+ end
247
+ File.write(page, open_fence + front + close_fence + body) if changed
248
+ end
249
+ end
250
+
251
+ # Posts and pages need to reference the theme's layouts. A site that already
252
+ # has its own layouts keeps them; these defaults only apply where there is
253
+ # nothing already.
254
+ create_file "src/_posts/_defaults.yml", force: false do
255
+ <<~YAML
256
+ layout: shoreditch/post
257
+ YAML
258
+ end
259
+
260
+ say <<~TEXT, :green
261
+
262
+ Shoreditch installed.
263
+
264
+ Next steps:
265
+
266
+ 1. Set `layout: shoreditch/page` on your standalone pages.
267
+ 2. Add these to src/_data/site_metadata.yml:
268
+
269
+ logo: /images/your-logo.png
270
+ logo_link: /about/
271
+ tagline: Your tagline
272
+
273
+ 3. Give pages a `nav_order:` to put them in the sidebar. Pages with
274
+ `exclude: true` never appear there.
275
+
276
+ The full option list is in the theme README.
277
+ TEXT