docula 0.90.0 → 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.
- package/dist/docula.d.ts +49 -1
- package/dist/docula.js +286 -184
- package/package.json +2 -2
- package/templates/classic/css/base.css +29 -0
- package/templates/classic/css/multipage.css +26 -0
- package/templates/classic/includes/multipage/header.hbs +5 -0
- package/templates/classic/includes/multipage/sidebar.hbs +7 -0
- package/templates/modern/css/home.css +37 -0
- package/templates/modern/css/styles.css +45 -0
- package/templates/modern/home.hbs +11 -0
- package/templates/modern/includes/header-bar.hbs +44 -0
- package/templates/modern/includes/scripts.hbs +55 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docula",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Beautiful Website for Your Projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/docula.js",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"test:e2e": "pnpm build && playwright test",
|
|
81
81
|
"generate-init-file": "tsx scripts/generate-init-file.ts",
|
|
82
82
|
"website:build": "node bin/docula.js build -s ./site -o ./site/dist",
|
|
83
|
-
"website:serve": "node bin/docula.js serve -s ./site -o ./site/dist -w -p 3333",
|
|
83
|
+
"website:serve": "pnpm build && node bin/docula.js serve -s ./site -o ./site/dist -w -p 3333",
|
|
84
84
|
"website:mega": "node bin/docula.js serve -s ./test/fixtures/mega-page-site --watch --clean",
|
|
85
85
|
"website:nohome": "node bin/docula.js serve -s ./test/fixtures/mega-page-site-no-home-page --watch --clean",
|
|
86
86
|
"website:changelog": "node bin/docula.js serve -s ./test/fixtures/changelog-site --watch --clean"
|
|
@@ -3,6 +3,35 @@
|
|
|
3
3
|
box-sizing: border-box;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
/* Mobile: prevent home page from scrolling vertically */
|
|
7
|
+
@media (max-width: 767px) {
|
|
8
|
+
.home {
|
|
9
|
+
height: 100dvh;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.home .home-hero {
|
|
16
|
+
flex: 1 1 auto;
|
|
17
|
+
height: auto;
|
|
18
|
+
padding: 1.5rem 0 1rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.home .home-hero img {
|
|
22
|
+
max-width: 8rem;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.home .home-actions {
|
|
26
|
+
padding-bottom: 1rem;
|
|
27
|
+
flex-shrink: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.home .home-container {
|
|
31
|
+
display: none;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
6
35
|
.hidden {
|
|
7
36
|
display: none;
|
|
8
37
|
}
|
|
@@ -127,6 +127,32 @@
|
|
|
127
127
|
align-items: center;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
.sidebar-links {
|
|
131
|
+
display: none;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@media screen and (min-width: 992px) {
|
|
135
|
+
.sidebar-links {
|
|
136
|
+
display: flex;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
gap: 0.5rem;
|
|
139
|
+
padding: 1rem 0;
|
|
140
|
+
border-top: 1px solid var(--border);
|
|
141
|
+
margin-top: 1rem;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.sidebar-header-link {
|
|
145
|
+
color: var(--sidebar-text);
|
|
146
|
+
text-decoration: none;
|
|
147
|
+
font-size: 0.875rem;
|
|
148
|
+
padding: 0.25rem 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.sidebar-header-link:hover {
|
|
152
|
+
text-decoration: underline;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
130
156
|
.header-logo {
|
|
131
157
|
flex-shrink: 0;
|
|
132
158
|
margin-right: 1.5rem;
|
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
<a class="header-logo" href="/">
|
|
6
6
|
<img src="/logo.svg" alt="logo" />
|
|
7
7
|
</a>
|
|
8
|
+
{{#if headerLinks}}
|
|
9
|
+
{{#each headerLinks}}
|
|
10
|
+
<a class="header-link" href="{{this.url}}" target="_blank" rel="noopener noreferrer">{{#if this.icon}}{{{this.icon}}} {{/if}}{{this.label}}</a>
|
|
11
|
+
{{/each}}
|
|
12
|
+
{{/if}}
|
|
8
13
|
<button id="open-sidebar" class="icon menu-btn">
|
|
9
14
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg>
|
|
10
15
|
<span>Menu</span>
|
|
@@ -36,6 +36,13 @@
|
|
|
36
36
|
{{/forEach}}
|
|
37
37
|
</ul>
|
|
38
38
|
|
|
39
|
+
{{#if headerLinks}}
|
|
40
|
+
<div class="sidebar-links">
|
|
41
|
+
{{#each headerLinks}}
|
|
42
|
+
<a class="sidebar-header-link" href="{{this.url}}" target="_blank" rel="noopener noreferrer">{{#if this.icon}}{{{this.icon}}} {{/if}}{{this.label}}</a>
|
|
43
|
+
{{/each}}
|
|
44
|
+
</div>
|
|
45
|
+
{{/if}}
|
|
39
46
|
</div>
|
|
40
47
|
</section>
|
|
41
48
|
|
|
@@ -82,6 +82,43 @@
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
/* Mobile adjustments */
|
|
86
|
+
@media (max-width: 767px) {
|
|
87
|
+
.home-hero {
|
|
88
|
+
min-height: auto;
|
|
89
|
+
padding: 2rem 1rem 1rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.home-hero img {
|
|
93
|
+
max-width: 8rem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.hero-container {
|
|
97
|
+
margin: 1rem auto;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.hero-container h1 {
|
|
101
|
+
font-size: 1.125rem;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.home-actions {
|
|
105
|
+
padding-bottom: 1rem;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.home-content {
|
|
109
|
+
padding: 0.75rem;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.home-content > section {
|
|
113
|
+
padding: 0.75rem 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.home-content .home-title {
|
|
117
|
+
font-size: 1.25rem;
|
|
118
|
+
margin-bottom: 0.5rem;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
85
122
|
/* Responsive hero */
|
|
86
123
|
@media (min-width: 768px) {
|
|
87
124
|
.home-hero { min-height: 50vh; }
|
|
@@ -137,6 +137,49 @@ body {
|
|
|
137
137
|
display: none;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
.cookie-auth-btn {
|
|
141
|
+
border: 1px solid var(--border);
|
|
142
|
+
border-radius: 4px;
|
|
143
|
+
padding: 4px 10px;
|
|
144
|
+
height: 30px;
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
gap: 6px;
|
|
148
|
+
background: transparent;
|
|
149
|
+
color: var(--fg);
|
|
150
|
+
font-size: 13px;
|
|
151
|
+
cursor: pointer;
|
|
152
|
+
text-decoration: none;
|
|
153
|
+
white-space: nowrap;
|
|
154
|
+
|
|
155
|
+
&:hover {
|
|
156
|
+
border-color: var(--border-hover);
|
|
157
|
+
background: var(--surface-hover);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.cookie-auth-btn--fixed {
|
|
162
|
+
position: fixed;
|
|
163
|
+
bottom: 16px;
|
|
164
|
+
left: 56px;
|
|
165
|
+
z-index: 50;
|
|
166
|
+
background: var(--surface);
|
|
167
|
+
border: 1px solid var(--border);
|
|
168
|
+
border-radius: 8px;
|
|
169
|
+
padding: 6px 12px;
|
|
170
|
+
height: auto;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.cookie-auth-btn--mobile {
|
|
174
|
+
width: 100%;
|
|
175
|
+
background: transparent;
|
|
176
|
+
border: none;
|
|
177
|
+
cursor: pointer;
|
|
178
|
+
text-align: left;
|
|
179
|
+
font-size: inherit;
|
|
180
|
+
color: inherit;
|
|
181
|
+
}
|
|
182
|
+
|
|
140
183
|
.mobile-menu-toggle {
|
|
141
184
|
display: none;
|
|
142
185
|
align-items: center;
|
|
@@ -512,6 +555,7 @@ body {
|
|
|
512
555
|
margin: 0 auto;
|
|
513
556
|
font-size: 15px;
|
|
514
557
|
line-height: 1.5;
|
|
558
|
+
overflow-wrap: break-word;
|
|
515
559
|
}
|
|
516
560
|
|
|
517
561
|
.home-content > section {
|
|
@@ -654,6 +698,7 @@ body {
|
|
|
654
698
|
margin-top: 12px;
|
|
655
699
|
font-size: 15px;
|
|
656
700
|
line-height: 1.6;
|
|
701
|
+
overflow-wrap: break-word;
|
|
657
702
|
}
|
|
658
703
|
|
|
659
704
|
.changelog-entry-nav {
|
|
@@ -44,6 +44,17 @@
|
|
|
44
44
|
</main>
|
|
45
45
|
{{/if}}
|
|
46
46
|
|
|
47
|
+
{{#if cookieAuth}}
|
|
48
|
+
<a href="{{cookieAuth.loginUrl}}" class="cookie-auth-btn cookie-auth-btn--fixed" id="cookie-auth-login">
|
|
49
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" x2="3" y1="12" y2="12"/></svg>
|
|
50
|
+
<span>Log In</span>
|
|
51
|
+
</a>
|
|
52
|
+
<button class="cookie-auth-btn cookie-auth-btn--fixed" id="cookie-auth-logout" style="display:none">
|
|
53
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/></svg>
|
|
54
|
+
<span>Log Out</span>
|
|
55
|
+
</button>
|
|
56
|
+
{{/if}}
|
|
57
|
+
|
|
47
58
|
{{> theme-toggle fixed=true }}
|
|
48
59
|
|
|
49
60
|
{{> footer }}
|
|
@@ -26,7 +26,29 @@
|
|
|
26
26
|
<span>Changelog</span>
|
|
27
27
|
</a>
|
|
28
28
|
{{/if}}
|
|
29
|
+
{{#if headerLinks}}
|
|
30
|
+
{{#each headerLinks}}
|
|
31
|
+
<a class="header-bottom__item" href="{{this.url}}" target="_blank" rel="noopener noreferrer">
|
|
32
|
+
{{#if this.icon}}
|
|
33
|
+
{{{this.icon}}}
|
|
34
|
+
{{else}}
|
|
35
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>
|
|
36
|
+
{{/if}}
|
|
37
|
+
<span>{{this.label}}</span>
|
|
38
|
+
</a>
|
|
39
|
+
{{/each}}
|
|
40
|
+
{{/if}}
|
|
29
41
|
</nav>
|
|
42
|
+
{{#if cookieAuth}}
|
|
43
|
+
<a href="{{cookieAuth.loginUrl}}" class="cookie-auth-btn" id="cookie-auth-login">
|
|
44
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" x2="3" y1="12" y2="12"/></svg>
|
|
45
|
+
<span>Log In</span>
|
|
46
|
+
</a>
|
|
47
|
+
<button class="cookie-auth-btn" id="cookie-auth-logout" style="display:none">
|
|
48
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/></svg>
|
|
49
|
+
<span>Log Out</span>
|
|
50
|
+
</button>
|
|
51
|
+
{{/if}}
|
|
30
52
|
{{> theme-toggle }}
|
|
31
53
|
</div>
|
|
32
54
|
</div>
|
|
@@ -51,6 +73,28 @@
|
|
|
51
73
|
<span>Changelog</span>
|
|
52
74
|
</a>
|
|
53
75
|
{{/if}}
|
|
76
|
+
{{#if headerLinks}}
|
|
77
|
+
{{#each headerLinks}}
|
|
78
|
+
<a class="mobile-nav__item" href="{{this.url}}" target="_blank" rel="noopener noreferrer">
|
|
79
|
+
{{#if this.icon}}
|
|
80
|
+
{{{this.icon}}}
|
|
81
|
+
{{else}}
|
|
82
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>
|
|
83
|
+
{{/if}}
|
|
84
|
+
<span>{{this.label}}</span>
|
|
85
|
+
</a>
|
|
86
|
+
{{/each}}
|
|
87
|
+
{{/if}}
|
|
88
|
+
{{#if cookieAuth}}
|
|
89
|
+
<a class="mobile-nav__item" href="{{cookieAuth.loginUrl}}" id="cookie-auth-login-mobile">
|
|
90
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" x2="3" y1="12" y2="12"/></svg>
|
|
91
|
+
<span>Log In</span>
|
|
92
|
+
</a>
|
|
93
|
+
<button class="mobile-nav__item cookie-auth-btn--mobile" id="cookie-auth-logout-mobile" style="display:none">
|
|
94
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/></svg>
|
|
95
|
+
<span>Log Out</span>
|
|
96
|
+
</button>
|
|
97
|
+
{{/if}}
|
|
54
98
|
</nav>
|
|
55
99
|
<div class="mobile-sidebar__docs" id="mobile-sidebar-docs"></div>
|
|
56
100
|
</aside>
|
|
@@ -88,6 +88,61 @@
|
|
|
88
88
|
});
|
|
89
89
|
})();
|
|
90
90
|
</script>
|
|
91
|
+
{{#if cookieAuth}}
|
|
92
|
+
<div id="cookie-auth-config" hidden data-cookie-name="{{#if cookieAuth.cookieName}}{{cookieAuth.cookieName}}{{else}}token{{/if}}"{{#if cookieAuth.logoutUrl}} data-logout-url="{{cookieAuth.logoutUrl}}"{{/if}}></div>
|
|
93
|
+
<script>
|
|
94
|
+
(function() {
|
|
95
|
+
var configEl = document.getElementById('cookie-auth-config');
|
|
96
|
+
if (!configEl) return;
|
|
97
|
+
var cookieName = configEl.getAttribute('data-cookie-name');
|
|
98
|
+
var logoutUrl = configEl.getAttribute('data-logout-url');
|
|
99
|
+
function isSafeUrl(url) {
|
|
100
|
+
if (!url) return false;
|
|
101
|
+
try {
|
|
102
|
+
var parsed = new URL(url, window.location.origin);
|
|
103
|
+
return parsed.origin === window.location.origin;
|
|
104
|
+
} catch (e) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function hasCookie() {
|
|
109
|
+
return document.cookie.split(';').some(function(c) {
|
|
110
|
+
return c.trim().startsWith(cookieName + '=');
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function updateAuthUI() {
|
|
114
|
+
var loggedIn = hasCookie();
|
|
115
|
+
var els = [
|
|
116
|
+
{ login: document.getElementById('cookie-auth-login'), logout: document.getElementById('cookie-auth-logout') },
|
|
117
|
+
{ login: document.getElementById('cookie-auth-login-mobile'), logout: document.getElementById('cookie-auth-logout-mobile') }
|
|
118
|
+
];
|
|
119
|
+
els.forEach(function(pair) {
|
|
120
|
+
if (pair.login) pair.login.style.display = loggedIn ? 'none' : '';
|
|
121
|
+
if (pair.logout) pair.logout.style.display = loggedIn ? '' : 'none';
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
125
|
+
updateAuthUI();
|
|
126
|
+
var logoutEls = [
|
|
127
|
+
document.getElementById('cookie-auth-logout'),
|
|
128
|
+
document.getElementById('cookie-auth-logout-mobile')
|
|
129
|
+
];
|
|
130
|
+
logoutEls.forEach(function(el) {
|
|
131
|
+
if (el) {
|
|
132
|
+
el.addEventListener('click', function() {
|
|
133
|
+
if (isSafeUrl(logoutUrl)) {
|
|
134
|
+
window.location.href = logoutUrl;
|
|
135
|
+
} else {
|
|
136
|
+
document.cookie = cookieName + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
|
|
137
|
+
window.location.reload();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
})();
|
|
144
|
+
</script>
|
|
145
|
+
{{/if}}
|
|
91
146
|
<script defer>
|
|
92
147
|
document.addEventListener('DOMContentLoaded', () => {
|
|
93
148
|
const menuToggle = document.getElementById('mobile-menu-toggle');
|