fossbook 0.1.4 → 0.2.1
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.
- package/README.md +37 -10
- package/lib/all_posts.js +3 -3
- package/lib/index.js +42 -0
- package/lib/init.js +4 -1
- package/lib/mod/config.js +27 -4
- package/lib/mod/marked.js +67 -1
- package/lib/tag/index.js +4 -3
- package/package.json +1 -1
- package/themes/archie/assets/styles/main.css +60 -11
- package/themes/archie/layouts/all_posts.html +9 -4
- package/themes/archie/layouts/home.html +10 -5
- package/themes/archie/layouts/page.html +4 -4
- package/themes/archie/layouts/post.html +4 -4
- package/themes/archie/layouts/tag.html +4 -4
- package/themes/archie/layouts/tag_list.html +10 -5
package/README.md
CHANGED
|
@@ -105,12 +105,7 @@ module.exports = {
|
|
|
105
105
|
defaultLanguageInSubdir: false,
|
|
106
106
|
languages: {
|
|
107
107
|
en: { languageName: "English", locale: "en-US" },
|
|
108
|
-
ko: {
|
|
109
|
-
languageName: "한국어",
|
|
110
|
-
locale: "ko-KR",
|
|
111
|
-
blogName: "나의 블로그",
|
|
112
|
-
blogDescription: "한국어 블로그",
|
|
113
|
-
},
|
|
108
|
+
ko: { languageName: "한국어", locale: "ko-KR" },
|
|
114
109
|
},
|
|
115
110
|
|
|
116
111
|
// Optional comments (see "Comments" below)
|
|
@@ -132,6 +127,11 @@ module.exports = {
|
|
|
132
127
|
|
|
133
128
|
## Content Format
|
|
134
129
|
|
|
130
|
+
Fossbook supports GitHub Flavored Markdown plus extensions for image sizing
|
|
131
|
+
and alignment, captions, comic dialogue, aligned links, Mermaid diagrams, and
|
|
132
|
+
syntax-highlighted code. See [Fossbook Markdown](fossbook_markdown.md) for
|
|
133
|
+
syntax and examples.
|
|
134
|
+
|
|
135
135
|
### Post front-matter
|
|
136
136
|
|
|
137
137
|
```markdown
|
|
@@ -192,8 +192,6 @@ module.exports = {
|
|
|
192
192
|
ko: {
|
|
193
193
|
languageName: "한국어",
|
|
194
194
|
locale: "ko-KR",
|
|
195
|
-
blogName: "나의 블로그",
|
|
196
|
-
blogDescription: "한국어 블로그",
|
|
197
195
|
},
|
|
198
196
|
ja: {
|
|
199
197
|
languageName: "日本語",
|
|
@@ -203,14 +201,43 @@ module.exports = {
|
|
|
203
201
|
};
|
|
204
202
|
```
|
|
205
203
|
|
|
204
|
+
Put localized blog information in a sibling config file for each language. For
|
|
205
|
+
example, `fossbook.config.en.js` contains:
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
module.exports = {
|
|
209
|
+
blogName: "My Blog",
|
|
210
|
+
authorName: "Jane Doe",
|
|
211
|
+
authorDescription: "Open source developer and writer",
|
|
212
|
+
blogDescription: "An English-language blog",
|
|
213
|
+
};
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
And `fossbook.config.ko.js` contains:
|
|
217
|
+
|
|
218
|
+
```js
|
|
219
|
+
module.exports = {
|
|
220
|
+
blogName: "나의 블로그",
|
|
221
|
+
authorName: "이수현",
|
|
222
|
+
authorDescription: "오픈 소스 개발자이자 작가",
|
|
223
|
+
blogDescription: "한국어 블로그",
|
|
224
|
+
homeLabel: "대문",
|
|
225
|
+
allPostsLabel: "모든 글",
|
|
226
|
+
aboutLabel: "소개",
|
|
227
|
+
tagsLabel: "태그",
|
|
228
|
+
allTagsLabel: "모든 태그",
|
|
229
|
+
};
|
|
230
|
+
```
|
|
231
|
+
|
|
206
232
|
- `defaultLanguage` identifies the language represented by `index.md` and
|
|
207
233
|
`about.md`.
|
|
208
234
|
- `defaultLanguageInSubdir: false` keeps the default language at the site root.
|
|
209
235
|
Other languages are generated below their language code, such as `/ko/`.
|
|
210
236
|
- Set `defaultLanguageInSubdir: true` to generate the default language below
|
|
211
237
|
its code as well, such as `/en/`.
|
|
212
|
-
-
|
|
213
|
-
`
|
|
238
|
+
- Language config files use the main config filename with the language code
|
|
239
|
+
inserted before the extension: `fossbook.config.<language>.js`.
|
|
240
|
+
- Values omitted from a language config fall back to `fossbook.config.js`.
|
|
214
241
|
- `locale` controls language-specific date formatting.
|
|
215
242
|
- Language keys should use standard language tags such as `en`, `ko`, `ja`, or
|
|
216
243
|
`zh-Hant`.
|
package/lib/all_posts.js
CHANGED
|
@@ -9,15 +9,15 @@ module.exports = class AllPostsPage extends PageBase {
|
|
|
9
9
|
|
|
10
10
|
// posts: array of Page objects
|
|
11
11
|
generateContent(posts) {
|
|
12
|
-
const pageTitle = "All posts";
|
|
12
|
+
const pageTitle = this.config.allPostsLabel || "All posts";
|
|
13
13
|
const allPostsDir = path.join(this.config.dev.outdir, "all_posts");
|
|
14
14
|
if (!fs.existsSync(allPostsDir))
|
|
15
15
|
fs.mkdirSync(allPostsDir);
|
|
16
16
|
|
|
17
17
|
const data = { posts: posts, pageTitle: pageTitle };
|
|
18
|
-
this.url = `${this.config.blogsite}/
|
|
18
|
+
this.url = `${this.config.blogsite}/all_posts/`;
|
|
19
19
|
this.title = `${this.config.blogName}: ${data.pageTitle}`;
|
|
20
|
-
this.description =
|
|
20
|
+
this.description = pageTitle;
|
|
21
21
|
this.imageURL = this.config.image;
|
|
22
22
|
|
|
23
23
|
const templatePath = path.join(this.config.themePath, "layouts", "all_posts.html");
|
package/lib/index.js
CHANGED
|
@@ -75,6 +75,36 @@ function createAboutTranslations(languageConfigs) {
|
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
function createHomeTranslations(languageConfigs) {
|
|
79
|
+
return languageConfigs.map((config) => ({
|
|
80
|
+
language: config.language,
|
|
81
|
+
languageName: config.languageName,
|
|
82
|
+
path: config.basePath || "/",
|
|
83
|
+
url: `${config.blogsite}/`,
|
|
84
|
+
isDefault: config.language === config.defaultLanguage,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function createAllPostsTranslations(languageConfigs) {
|
|
89
|
+
return languageConfigs.map((config) => ({
|
|
90
|
+
language: config.language,
|
|
91
|
+
languageName: config.languageName,
|
|
92
|
+
path: `${config.basePath || "/"}all_posts/`,
|
|
93
|
+
url: `${config.blogsite}/all_posts/`,
|
|
94
|
+
isDefault: config.language === config.defaultLanguage,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function createTagListTranslations(languageConfigs) {
|
|
99
|
+
return languageConfigs.map((config) => ({
|
|
100
|
+
language: config.language,
|
|
101
|
+
languageName: config.languageName,
|
|
102
|
+
path: `${config.basePath || "/"}tags/`,
|
|
103
|
+
url: `${config.blogsite}/tags/`,
|
|
104
|
+
isDefault: config.language === config.defaultLanguage,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
|
|
78
108
|
function buildLanguage(config) {
|
|
79
109
|
fs.mkdirSync(config.dev.outdir, { recursive: true });
|
|
80
110
|
|
|
@@ -88,14 +118,17 @@ function buildLanguage(config) {
|
|
|
88
118
|
|
|
89
119
|
// Create home page and pagination in output/page directory
|
|
90
120
|
const homePagination = new HomePagination(config);
|
|
121
|
+
homePagination.translations = config.homeTranslations || [];
|
|
91
122
|
homePagination.generateContent(postObjects);
|
|
92
123
|
|
|
93
124
|
// Create all posts page in output/all_posts directory
|
|
94
125
|
const allPostsPage = new AllPostsPage(config);
|
|
126
|
+
allPostsPage.translations = config.allPostsTranslations || [];
|
|
95
127
|
allPostsPage.generateContent(postObjects);
|
|
96
128
|
|
|
97
129
|
// Create tag pages in output/tags directory
|
|
98
130
|
const tagPages = new TagPages(config);
|
|
131
|
+
tagPages.translations = config.tagListTranslations || [];
|
|
99
132
|
tagPages.generateContent(postObjects);
|
|
100
133
|
|
|
101
134
|
// Create about page in output/about directory
|
|
@@ -132,9 +165,15 @@ function build(config) {
|
|
|
132
165
|
const languageConfigs = config.languageConfigs || [config];
|
|
133
166
|
const postTranslationIndex = createPostTranslationIndex(languageConfigs);
|
|
134
167
|
const aboutTranslations = createAboutTranslations(languageConfigs);
|
|
168
|
+
const homeTranslations = createHomeTranslations(languageConfigs);
|
|
169
|
+
const allPostsTranslations = createAllPostsTranslations(languageConfigs);
|
|
170
|
+
const tagListTranslations = createTagListTranslations(languageConfigs);
|
|
135
171
|
languageConfigs.forEach((languageConfig) => {
|
|
136
172
|
languageConfig.postTranslationIndex = postTranslationIndex;
|
|
137
173
|
languageConfig.aboutTranslations = aboutTranslations;
|
|
174
|
+
languageConfig.homeTranslations = homeTranslations;
|
|
175
|
+
languageConfig.allPostsTranslations = allPostsTranslations;
|
|
176
|
+
languageConfig.tagListTranslations = tagListTranslations;
|
|
138
177
|
});
|
|
139
178
|
languageConfigs.forEach(buildLanguage);
|
|
140
179
|
|
|
@@ -150,4 +189,7 @@ module.exports = {
|
|
|
150
189
|
buildLanguage,
|
|
151
190
|
createPostTranslationIndex,
|
|
152
191
|
createAboutTranslations,
|
|
192
|
+
createHomeTranslations,
|
|
193
|
+
createAllPostsTranslations,
|
|
194
|
+
createTagListTranslations,
|
|
153
195
|
};
|
package/lib/init.js
CHANGED
|
@@ -124,8 +124,11 @@ function initProject(options = {}) {
|
|
|
124
124
|
defaultLanguageInSubdir: false,
|
|
125
125
|
// languages: {
|
|
126
126
|
// en: { languageName: "English", locale: "en-US" },
|
|
127
|
-
// ko: { languageName: "한국어", locale: "ko-KR"
|
|
127
|
+
// ko: { languageName: "한국어", locale: "ko-KR" },
|
|
128
128
|
// },
|
|
129
|
+
// Add localized blog information to fossbook.config.en.js,
|
|
130
|
+
// fossbook.config.ko.js, and so on. Menu labels can also be localized with
|
|
131
|
+
// homeLabel, allPostsLabel, aboutLabel, tagsLabel, and allTagsLabel.
|
|
129
132
|
|
|
130
133
|
// Comment system (optional)
|
|
131
134
|
// comments: { provider: "utterances", repo: "user/repo", issueTerm: "pathname", theme: "github-light" },
|
package/lib/mod/config.js
CHANGED
|
@@ -98,12 +98,12 @@ function loadConfig(configPath) {
|
|
|
98
98
|
// Normalize postsPath into a bare segment without surrounding slashes
|
|
99
99
|
merged.postsPath = (merged.postsPath || "").replace(/^\/+|\/+$/g, "");
|
|
100
100
|
|
|
101
|
-
merged.languageConfigs = createLanguageConfigs(merged);
|
|
101
|
+
merged.languageConfigs = createLanguageConfigs(merged, resolvedConfigPath);
|
|
102
102
|
|
|
103
103
|
return merged;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
function createLanguageConfigs(config) {
|
|
106
|
+
function createLanguageConfigs(config, configPath) {
|
|
107
107
|
const configuredLanguages = config.languages;
|
|
108
108
|
const hasMultipleLanguages = configuredLanguages !== null && configuredLanguages !== undefined;
|
|
109
109
|
const languages = hasMultipleLanguages
|
|
@@ -125,6 +125,10 @@ function createLanguageConfigs(config) {
|
|
|
125
125
|
throw new Error(`languages.${language} must be an object`);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
const fileOverrides = configPath
|
|
129
|
+
? loadLanguageConfig(configPath, language)
|
|
130
|
+
: {};
|
|
131
|
+
|
|
128
132
|
const useSubdirectory = config.defaultLanguageInSubdir || language !== config.defaultLanguage;
|
|
129
133
|
const languagePrefix = useSubdirectory ? language : "";
|
|
130
134
|
const basePath = appendPathSegment(config.basePath, languagePrefix);
|
|
@@ -133,9 +137,12 @@ function createLanguageConfigs(config) {
|
|
|
133
137
|
return {
|
|
134
138
|
...config,
|
|
135
139
|
...overrides,
|
|
140
|
+
...fileOverrides,
|
|
141
|
+
defaultLanguage: config.defaultLanguage,
|
|
142
|
+
defaultLanguageInSubdir: config.defaultLanguageInSubdir,
|
|
136
143
|
language,
|
|
137
|
-
languageName: overrides.languageName || language,
|
|
138
|
-
locale: overrides.locale || language,
|
|
144
|
+
languageName: fileOverrides.languageName || overrides.languageName || language,
|
|
145
|
+
locale: fileOverrides.locale || overrides.locale || language,
|
|
139
146
|
languagePrefix,
|
|
140
147
|
basePath,
|
|
141
148
|
blogsite,
|
|
@@ -149,6 +156,22 @@ function createLanguageConfigs(config) {
|
|
|
149
156
|
});
|
|
150
157
|
}
|
|
151
158
|
|
|
159
|
+
function loadLanguageConfig(configPath, language) {
|
|
160
|
+
const extension = path.extname(configPath) || ".js";
|
|
161
|
+
const configStem = extension
|
|
162
|
+
? configPath.slice(0, -extension.length)
|
|
163
|
+
: configPath;
|
|
164
|
+
const languageConfigPath = `${configStem}.${language}${extension}`;
|
|
165
|
+
|
|
166
|
+
if (!fs.existsSync(languageConfigPath)) return {};
|
|
167
|
+
|
|
168
|
+
const languageConfig = require(languageConfigPath);
|
|
169
|
+
if (!languageConfig || typeof languageConfig !== "object" || Array.isArray(languageConfig)) {
|
|
170
|
+
throw new Error(`${path.basename(languageConfigPath)} must export an object`);
|
|
171
|
+
}
|
|
172
|
+
return languageConfig;
|
|
173
|
+
}
|
|
174
|
+
|
|
152
175
|
function appendPathSegment(basePath, segment) {
|
|
153
176
|
const normalizedBase = `/${basePath || ""}`.replace(/\/{2,}/g, "/");
|
|
154
177
|
const withTrailingSlash = normalizedBase.endsWith("/")
|
package/lib/mod/marked.js
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
const marked = require("marked");
|
|
2
2
|
const hljs = require("highlight.js");
|
|
3
3
|
|
|
4
|
+
function escapeAttribute(value) {
|
|
5
|
+
return value
|
|
6
|
+
.replace(/&/g, "&")
|
|
7
|
+
.replace(/"/g, """)
|
|
8
|
+
.replace(/</g, "<")
|
|
9
|
+
.replace(/>/g, ">");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function parsePanelAttributes(source) {
|
|
13
|
+
const attributes = {};
|
|
14
|
+
const attributePattern = /([a-z][a-z-]*)="([^"]*)"/gy;
|
|
15
|
+
let offset = 0;
|
|
16
|
+
|
|
17
|
+
while (offset < source.length) {
|
|
18
|
+
while (source[offset] === " " || source[offset] === "\t") offset += 1;
|
|
19
|
+
if (offset === source.length) break;
|
|
20
|
+
|
|
21
|
+
attributePattern.lastIndex = offset;
|
|
22
|
+
const match = attributePattern.exec(source);
|
|
23
|
+
if (!match) throw new Error(`Invalid panels attribute near: ${source.slice(offset)}`);
|
|
24
|
+
if (match[1] !== "columns" && match[1] !== "label") {
|
|
25
|
+
throw new Error(`Unsupported panels attribute: ${match[1]}`);
|
|
26
|
+
}
|
|
27
|
+
if (Object.hasOwn(attributes, match[1])) {
|
|
28
|
+
throw new Error(`Duplicate panels attribute: ${match[1]}`);
|
|
29
|
+
}
|
|
30
|
+
attributes[match[1]] = match[2];
|
|
31
|
+
offset = attributePattern.lastIndex;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const columns = attributes.columns === undefined ? 2 : Number(attributes.columns);
|
|
35
|
+
if (!Number.isInteger(columns) || columns < 1 || columns > 6) {
|
|
36
|
+
throw new Error("Panel columns must be an integer from 1 to 6");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return { columns, label: attributes.label };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const panelsExtension = {
|
|
43
|
+
name: "panels",
|
|
44
|
+
level: "block",
|
|
45
|
+
start(source) {
|
|
46
|
+
return source.match(/^:::panels(?:[ \t]|$)/m)?.index;
|
|
47
|
+
},
|
|
48
|
+
tokenizer(source) {
|
|
49
|
+
const match = /^:::panels([^\n]*)\n([\s\S]*?)\n:::(?:\n|$)/.exec(source);
|
|
50
|
+
if (!match) return undefined;
|
|
51
|
+
|
|
52
|
+
const attributes = parsePanelAttributes(match[1].trim());
|
|
53
|
+
return {
|
|
54
|
+
type: "panels",
|
|
55
|
+
raw: match[0],
|
|
56
|
+
columns: attributes.columns,
|
|
57
|
+
label: attributes.label,
|
|
58
|
+
tokens: this.lexer.blockTokens(match[2]),
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
renderer(token) {
|
|
62
|
+
const label = token.label
|
|
63
|
+
? ` role="group" aria-label="${escapeAttribute(token.label)}"`
|
|
64
|
+
: "";
|
|
65
|
+
return `<div class="panel-group" style="--panel-columns: ${token.columns};"${label}>\n${this.parser.parse(token.tokens)}</div>\n`;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
4
69
|
marked.setOptions({
|
|
5
70
|
renderer: new marked.Renderer(),
|
|
6
71
|
pedantic: false,
|
|
@@ -66,7 +131,7 @@ const renderer = {
|
|
|
66
131
|
// Construct the image tag with optional size and title
|
|
67
132
|
let imageTag = `<img src="${href}" alt="${text}"`;
|
|
68
133
|
if (size) {
|
|
69
|
-
imageTag += ` style="width: ${size};"`;
|
|
134
|
+
imageTag += ` class="sized-image" style="width: ${size};"`;
|
|
70
135
|
}
|
|
71
136
|
imageTag += ">";
|
|
72
137
|
|
|
@@ -114,6 +179,7 @@ const renderer = {
|
|
|
114
179
|
};
|
|
115
180
|
|
|
116
181
|
marked.use({
|
|
182
|
+
extensions: [panelsExtension],
|
|
117
183
|
renderer,
|
|
118
184
|
hooks: {
|
|
119
185
|
postprocess(html) {
|
package/lib/tag/index.js
CHANGED
|
@@ -46,10 +46,11 @@ module.exports = class TagList extends PageBase {
|
|
|
46
46
|
if (!fs.existsSync(tagsDir))
|
|
47
47
|
fs.mkdirSync(tagsDir);
|
|
48
48
|
|
|
49
|
+
const pageTitle = this.config.allTagsLabel || "All tags";
|
|
49
50
|
this.imageURL = this.config.image;
|
|
50
|
-
this.description =
|
|
51
|
-
const data = { tags: tagArray, pageTitle
|
|
52
|
-
this.url = `${this.config.blogsite}/
|
|
51
|
+
this.description = pageTitle;
|
|
52
|
+
const data = { tags: tagArray, pageTitle };
|
|
53
|
+
this.url = `${this.config.blogsite}/tags/`;
|
|
53
54
|
this.title = `${this.config.blogName}: ${data.pageTitle}`;
|
|
54
55
|
|
|
55
56
|
const templatePath = path.join(this.config.themePath, "layouts", "tag_list.html");
|
package/package.json
CHANGED
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
a {
|
|
161
|
-
border-bottom:
|
|
161
|
+
border-bottom: 2px solid var(--maincolor);
|
|
162
162
|
color: inherit;
|
|
163
163
|
text-decoration: none;
|
|
164
164
|
}
|
|
@@ -223,6 +223,46 @@
|
|
|
223
223
|
figure img {
|
|
224
224
|
max-height: 500px;
|
|
225
225
|
}
|
|
226
|
+
|
|
227
|
+
.panel-group {
|
|
228
|
+
display: grid;
|
|
229
|
+
grid-template-columns: repeat(var(--panel-columns), minmax(0, 1fr));
|
|
230
|
+
gap: 1.5rem;
|
|
231
|
+
align-items: start;
|
|
232
|
+
margin: 1.5rem 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.panel-group .image-container,
|
|
236
|
+
.panel-group figure {
|
|
237
|
+
min-width: 0;
|
|
238
|
+
width: 100%;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.panel-group figure {
|
|
242
|
+
display: block;
|
|
243
|
+
padding: 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.panel-group img {
|
|
247
|
+
display: block;
|
|
248
|
+
height: auto;
|
|
249
|
+
width: 100%;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.panel-group figcaption {
|
|
253
|
+
margin-top: 0.75rem;
|
|
254
|
+
text-align: center;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
@media screen and (max-width: 599px) {
|
|
258
|
+
.panel-group {
|
|
259
|
+
grid-template-columns: 1fr;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.sized-image {
|
|
263
|
+
width: 100% !important;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
226
266
|
|
|
227
267
|
@media screen and (min-width: 600px) {
|
|
228
268
|
figure {
|
|
@@ -291,16 +331,20 @@
|
|
|
291
331
|
font-size: 1.5rem;
|
|
292
332
|
}
|
|
293
333
|
h1, h2, h3, h4, h5, h6 {
|
|
294
|
-
|
|
334
|
+
line-height: 1.3;
|
|
335
|
+
margin-bottom: 0.75em;
|
|
295
336
|
margin-top: 2em;
|
|
296
337
|
}
|
|
297
|
-
|
|
298
|
-
h1
|
|
299
|
-
h2
|
|
300
|
-
h3
|
|
301
|
-
h4
|
|
302
|
-
|
|
303
|
-
|
|
338
|
+
|
|
339
|
+
h1 { font-size: 1.4rem; }
|
|
340
|
+
h2 { font-size: 1.2rem; }
|
|
341
|
+
h3 { font-size: 1.1rem; }
|
|
342
|
+
h4 {
|
|
343
|
+
font-size: 1rem;
|
|
344
|
+
font-weight: 700;
|
|
345
|
+
}
|
|
346
|
+
h5 { font-size: 0.9rem; }
|
|
347
|
+
h6 { font-size: 0.8rem; }
|
|
304
348
|
|
|
305
349
|
.meta {
|
|
306
350
|
color: #999;
|
|
@@ -331,6 +375,10 @@
|
|
|
331
375
|
nav {
|
|
332
376
|
font-family: 'Roboto Mono', monospace;
|
|
333
377
|
}
|
|
378
|
+
html:lang(ko) header,
|
|
379
|
+
html:lang(ko) nav {
|
|
380
|
+
font-family: 'NanumSquareNeo', sans-serif;
|
|
381
|
+
}
|
|
334
382
|
nav.post-navigation {
|
|
335
383
|
display: flex;
|
|
336
384
|
justify-content: end;
|
|
@@ -365,6 +413,7 @@
|
|
|
365
413
|
|
|
366
414
|
/* Common */
|
|
367
415
|
.title h1 {
|
|
416
|
+
font-size: 1.7rem;
|
|
368
417
|
margin-bottom: 0;
|
|
369
418
|
}
|
|
370
419
|
|
|
@@ -394,7 +443,7 @@
|
|
|
394
443
|
}
|
|
395
444
|
|
|
396
445
|
.callout a {
|
|
397
|
-
border-bottom:
|
|
446
|
+
border-bottom: 2px solid #fff;
|
|
398
447
|
}
|
|
399
448
|
|
|
400
449
|
.callout a:hover {
|
|
@@ -410,7 +459,7 @@
|
|
|
410
459
|
content: "🏷 ";
|
|
411
460
|
}
|
|
412
461
|
.tags a{
|
|
413
|
-
border-bottom:
|
|
462
|
+
border-bottom: 2px solid var(--maincolor);
|
|
414
463
|
}
|
|
415
464
|
.tags a:hover{
|
|
416
465
|
color:white;
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
<!-- Google tag (gtag.js) -->
|
|
11
11
|
${page.config.googleAnalyticsID ? page.googleAnalytics(page.config.googleAnalyticsID) : ""}
|
|
12
12
|
<title>${page.config.blogName}: ${data.pageTitle}</title>
|
|
13
|
+
<link rel="canonical" href="${page.url}" />
|
|
14
|
+
${page.alternateLanguageLinks()}
|
|
13
15
|
${page.openGraph("website")}
|
|
14
16
|
</head>
|
|
15
17
|
<body>
|
|
@@ -17,13 +19,16 @@
|
|
|
17
19
|
<header>
|
|
18
20
|
<div class="main">${page.config.blogName}</div>
|
|
19
21
|
<nav>
|
|
20
|
-
<a href="${page.config.basePath}"
|
|
22
|
+
<a href="${page.config.basePath}">${page.config.homeLabel || "Home"}</a>
|
|
21
23
|
${data.pageTitle}
|
|
22
|
-
<a href="${page.config.basePath}about"
|
|
23
|
-
<a href="${page.config.basePath}tags"
|
|
24
|
+
<a href="${page.config.basePath}about">${page.config.aboutLabel || "About"}</a>
|
|
25
|
+
<a href="${page.config.basePath}tags">${page.config.tagsLabel || "Tags"}</a>
|
|
24
26
|
</nav>
|
|
25
27
|
</header>
|
|
26
|
-
<
|
|
28
|
+
<div class="title">
|
|
29
|
+
<h1 class="page-title">${data.pageTitle}</h1>
|
|
30
|
+
${page.languageSwitcher()}
|
|
31
|
+
</div>
|
|
27
32
|
<ul class="posts">
|
|
28
33
|
${data.posts
|
|
29
34
|
.map(
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
${page.config.googleAnalyticsID ? page.googleAnalytics(page.config.googleAnalyticsID) : ""}
|
|
11
11
|
<title>${page.config.blogName}</title>
|
|
12
12
|
<meta name="description" content="${page.config.blogDescription}" />
|
|
13
|
+
<link rel="canonical" href="${page.url}" />
|
|
14
|
+
${page.alternateLanguageLinks()}
|
|
13
15
|
${page.openGraph("website")}
|
|
14
16
|
<!-- Twitter Card -->
|
|
15
17
|
${page.twitterCard("summary")}
|
|
@@ -17,12 +19,15 @@
|
|
|
17
19
|
<body>
|
|
18
20
|
<div class="content">
|
|
19
21
|
<header>
|
|
20
|
-
<div
|
|
22
|
+
<div>
|
|
23
|
+
<div class="main">${page.config.blogName}</div>
|
|
24
|
+
${page.languageSwitcher()}
|
|
25
|
+
</div>
|
|
21
26
|
<nav>
|
|
22
|
-
Home
|
|
23
|
-
<a href="${page.config.basePath}all_posts"
|
|
24
|
-
<a href="${page.config.basePath}about"
|
|
25
|
-
<a href="${page.config.basePath}tags"
|
|
27
|
+
${page.config.homeLabel || "Home"}
|
|
28
|
+
<a href="${page.config.basePath}all_posts">${page.config.allPostsLabel || "All posts"}</a>
|
|
29
|
+
<a href="${page.config.basePath}about">${page.config.aboutLabel || "About"}</a>
|
|
30
|
+
<a href="${page.config.basePath}tags">${page.config.tagsLabel || "Tags"}</a>
|
|
26
31
|
</nav>
|
|
27
32
|
</header>
|
|
28
33
|
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
${page.config.blogName}
|
|
29
29
|
</div>
|
|
30
30
|
<nav class="site-navigation">
|
|
31
|
-
<a href="${page.config.basePath}"
|
|
32
|
-
<a href="${page.config.basePath}all_posts"
|
|
33
|
-
About
|
|
34
|
-
<a href="${page.config.basePath}tags"
|
|
31
|
+
<a href="${page.config.basePath}">${page.config.homeLabel || "Home"}</a>
|
|
32
|
+
<a href="${page.config.basePath}all_posts">${page.config.allPostsLabel || "All posts"}</a>
|
|
33
|
+
${page.config.aboutLabel || "About"}
|
|
34
|
+
<a href="${page.config.basePath}tags">${page.config.tagsLabel || "Tags"}</a>
|
|
35
35
|
</nav>
|
|
36
36
|
</header>
|
|
37
37
|
<main>
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
${page.config.blogName}
|
|
43
43
|
</div>
|
|
44
44
|
<nav class="site-navigation">
|
|
45
|
-
<a href="${page.config.basePath}"
|
|
46
|
-
<a href="${page.config.basePath}all_posts"
|
|
47
|
-
<a href="${page.config.basePath}about"
|
|
48
|
-
<a href="${page.config.basePath}tags"
|
|
45
|
+
<a href="${page.config.basePath}">${page.config.homeLabel || "Home"}</a>
|
|
46
|
+
<a href="${page.config.basePath}all_posts">${page.config.allPostsLabel || "All posts"}</a>
|
|
47
|
+
<a href="${page.config.basePath}about">${page.config.aboutLabel || "About"}</a>
|
|
48
|
+
<a href="${page.config.basePath}tags">${page.config.tagsLabel || "Tags"}</a>
|
|
49
49
|
</nav>
|
|
50
50
|
</header>
|
|
51
51
|
<main>
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
<header>
|
|
18
18
|
<div class="main">${page.config.blogName}</div>
|
|
19
19
|
<nav>
|
|
20
|
-
<a href="${page.config.basePath}"
|
|
21
|
-
<a href="${page.config.basePath}all_posts"
|
|
22
|
-
<a href="${page.config.basePath}about"
|
|
23
|
-
<a href="${page.config.basePath}tags"
|
|
20
|
+
<a href="${page.config.basePath}">${page.config.homeLabel || "Home"}</a>
|
|
21
|
+
<a href="${page.config.basePath}all_posts">${page.config.allPostsLabel || "All posts"}</a>
|
|
22
|
+
<a href="${page.config.basePath}about">${page.config.aboutLabel || "About"}</a>
|
|
23
|
+
<a href="${page.config.basePath}tags">${page.config.tagsLabel || "Tags"}</a>
|
|
24
24
|
</nav>
|
|
25
25
|
</header>
|
|
26
26
|
<h1 class="page-title">Entries tagged - "${data.tag}"</h1>
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
<!-- Google tag (gtag.js) -->
|
|
12
12
|
${page.config.googleAnalyticsID ? page.googleAnalytics(page.config.googleAnalyticsID) : ""}
|
|
13
13
|
<title>${page.config.blogName}: ${data.pageTitle}</title>
|
|
14
|
+
<link rel="canonical" href="${page.url}" />
|
|
15
|
+
${page.alternateLanguageLinks()}
|
|
14
16
|
${page.openGraph("website")}
|
|
15
17
|
</head>
|
|
16
18
|
<body>
|
|
@@ -18,13 +20,16 @@
|
|
|
18
20
|
<header>
|
|
19
21
|
<div class="main">${page.config.blogName}</div>
|
|
20
22
|
<nav>
|
|
21
|
-
<a href="${page.config.basePath}"
|
|
22
|
-
<a href="${page.config.basePath}all_posts"
|
|
23
|
-
<a href="${page.config.basePath}about"
|
|
24
|
-
Tags
|
|
23
|
+
<a href="${page.config.basePath}">${page.config.homeLabel || "Home"}</a>
|
|
24
|
+
<a href="${page.config.basePath}all_posts">${page.config.allPostsLabel || "All posts"}</a>
|
|
25
|
+
<a href="${page.config.basePath}about">${page.config.aboutLabel || "About"}</a>
|
|
26
|
+
${page.config.tagsLabel || "Tags"}
|
|
25
27
|
</nav>
|
|
26
28
|
</header>
|
|
27
|
-
<
|
|
29
|
+
<div class="title">
|
|
30
|
+
<h1 class="page-title">${data.pageTitle}</h1>
|
|
31
|
+
${page.languageSwitcher()}
|
|
32
|
+
</div>
|
|
28
33
|
<div class="tag-cloud">
|
|
29
34
|
<ul class="tags">
|
|
30
35
|
${data.tags
|