Skip to content

Commit e0259d4

Browse files
committed
doc: modernize site + dark theme
- remove the default ascii doctor theme - add dark theme - use atom-one-dark as highlight - fix #3859
1 parent e94507b commit e0259d4

File tree

20 files changed

+1245
-266
lines changed

20 files changed

+1245
-266
lines changed

docs/asciidoc/configuration.adoc

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,15 @@ To ensure environment-specific logging works correctly, avoid using **static** l
168168

169169
==== Application Properties
170170

171+
[cols="2,1,3"]
171172
|===
172-
|Property | Description | Default
173+
|Property | Default | Description
173174

174-
|`application.charset` | Charset for encoding/decoding and templates. | `UTF-8`
175-
|`application.env` | Active environment names. Jooby optimizes performance for non-`dev` environments. | `dev`
176-
|`application.lang` | Supported languages for `Context.locale()`. | `Locale.getDefault()`
177-
|`application.tmpdir` | Temporary directory for the application. | `tmp`
178-
|`application.pid` | The JVM process ID. | System assigned
175+
|`application.charset` | `UTF-8` | Charset for encoding/decoding and templates.
176+
|`application.env` | `dev` | Active environment names. Jooby optimizes performance for non-`dev` environments.
177+
|`application.lang` | `Locale.getDefault()` | Supported languages for `Context.locale()`.
178+
|`application.tmpdir` | `tmp` | Temporary directory for the application.
179+
|`application.pid` | System assigned | The JVM process ID.
179180
|===
180181

181182
See javadoc:AvailableSettings[] for a complete reference.

docs/asciidoc/core.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
== Core
2+
[.lead]
3+
The foundational building blocks of your Jooby application. This section covers how to bootstrap the server, manage application environments and configuration, and leverage the modular architecture that makes Jooby both lightweight and highly extensible.
24

35
include::routing.adoc[]
46

docs/asciidoc/docinfo-footer.html

Lines changed: 124 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,46 @@
1+
<button id="theme-toggle" class="theme-toggle" aria-label="Toggle Dark Mode">
2+
<svg class="sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2.25a.75.75 0 01.75.75v2.25a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.591 1.59a.75.75 0 101.06 1.061l1.591-1.59zM21.75 12a.75.75 0 01-.75.75h-2.25a.75.75 0 010-1.5H21a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 10-1.061 1.06l1.59 1.591zM12 18.75a.75.75 0 01.75.75V21a.75.75 0 01-1.5 0v-1.5a.75.75 0 01.75-.75zM6.166 18.894a.75.75 0 01-1.06-1.06l1.59-1.591a.75.75 0 111.061 1.06l-1.59 1.591zM2.25 12a.75.75 0 01.75-.75h2.25a.75.75 0 010 1.5H3a.75.75 0 01-.75-.75zM5.106 6.166a.75.75 0 011.06-1.06l1.591 1.59a.75.75 0 11-1.06 1.061l-1.591-1.59z"/></svg>
3+
<svg class="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M9.528 1.718a.75.75 0 01.162.819A8.97 8.97 0 009 6a9 9 0 009 9 8.97 8.97 0 003.463-.69.75.75 0 01.981.98 10.503 10.503 0 01-9.694 6.46c-5.799 0-10.5-4.701-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 01.818.162z" clip-rule="evenodd"/></svg>
4+
</button>
5+
16
<script src="/js/clipboard.min.js"></script>
27
<script src="/js/toc.js"></script>
38

49
<script>
5-
// Replacing $(function() { ... }) with native DOMContentLoaded
610
document.addEventListener('DOMContentLoaded', () => {
7-
/** Tabs: */
11+
12+
/** 1. Theme Switcher Logic */
13+
const themeToggle = document.getElementById('theme-toggle');
14+
const htmlElement = document.documentElement;
15+
const hljsThemeLink = document.getElementById('hljs-theme'); // Grab the CSS link
16+
17+
if (themeToggle) {
18+
themeToggle.addEventListener('click', () => {
19+
if (htmlElement.getAttribute('data-theme') === 'dark') {
20+
// Switch to Light Mode
21+
htmlElement.removeAttribute('data-theme');
22+
localStorage.setItem('jooby-theme', 'light');
23+
24+
// Switch code block to Agate
25+
if (hljsThemeLink) hljsThemeLink.href = 'js/styles/agate.min.css';
26+
27+
} else {
28+
// Switch to Dark Mode
29+
htmlElement.setAttribute('data-theme', 'dark');
30+
localStorage.setItem('jooby-theme', 'dark');
31+
32+
// Switch code block to Atom One Dark
33+
if (hljsThemeLink) hljsThemeLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css';
34+
}
35+
});
36+
}
37+
38+
/** 2. Tabs Logic */
839
const tabButtons = document.querySelectorAll('.primary .switch .switch--item');
940
const contents = document.querySelectorAll('.primary .content');
1041

1142
tabButtons.forEach(button => {
1243
button.addEventListener('click', function () {
13-
// Extract option number (e.g., '1' from 'option-1')
1444
const match = this.className.match(/option-(\d+)/);
1545
if (!match) return;
1646
const option = match[1];
@@ -28,11 +58,100 @@
2858
});
2959
});
3060

31-
/** Clipboard.js Initialization */
32-
// Note: Since you're already loading clipboard.min.js, we just use the native constructor
61+
/** 3. Clipboard.js Initialization */
3362
const clipboard = new ClipboardJS('.clipboard');
3463
clipboard.on('success', (e) => {
3564
e.clearSelection();
65+
const btn = e.trigger;
66+
const originalHTML = btn.innerHTML;
67+
68+
// Temporarily change background and insert a checkmark SVG
69+
btn.style.backgroundColor = '#10b981'; // Tailwind emerald-500
70+
btn.style.borderColor = '#059669';
71+
btn.innerHTML = `<svg fill="none" stroke="white" stroke-width="2.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"></path></svg>`;
72+
73+
// Revert back after 2 seconds
74+
setTimeout(() => {
75+
btn.style.backgroundColor = '';
76+
btn.style.borderColor = '';
77+
btn.innerHTML = originalHTML;
78+
}, 2000);
3679
});
3780
});
81+
/** 4. Code Callout Badges (Zero-Flash & Auto-Format) */
82+
document.querySelectorAll('pre.highlightjs').forEach(pre => {
83+
// Check every 10ms if highlight.js has finished formatting this block
84+
const checkInterval = setInterval(() => {
85+
if (pre.dataset.highlighted === "yes" || pre.querySelector('.hljs')) {
86+
clearInterval(checkInterval);
87+
88+
const codeEl = pre.querySelector('code');
89+
if (codeEl) {
90+
// Upgraded regex to handle consecutive callouts like: // (1) (2)
91+
// The "Lookahead" (?= ... ) now checks if the rest of the line
92+
// is empty OR contains subsequent (N) callout numbers.
93+
const calloutRegex = /(\/\/\s*|\s+)\(\s*(?:<[^>]+>\s*)*(\d+)\s*(?:<[^>]+>\s*)*\)(?=\s*(?:<[^>]+>\s*)*(?:\(\s*(?:<[^>]+>\s*)*\d+\s*(?:<[^>]+>\s*)*\)\s*(?:<[^>]+>\s*)*)*(\n|<|$))/g;
94+
95+
codeEl.innerHTML = codeEl.innerHTML.replace(
96+
calloutRegex,
97+
(match, prefix, num) => {
98+
// Injects a hidden "//" before EVERY badge so that
99+
// multiple badges paste safely as "// 1 // 2"
100+
return ` <span class="visually-hidden">//</span> <span class="conum-badge">${num}</span>`;
101+
}
102+
);
103+
}
104+
105+
// Reveal the block smoothly
106+
pre.classList.add('badges-loaded');
107+
}
108+
}, 10);
109+
110+
// Fallback: Reveal the block anyway after 500ms
111+
setTimeout(() => {
112+
pre.classList.add('badges-loaded');
113+
clearInterval(checkInterval);
114+
}, 500);
115+
});
116+
/** 5. Copy Header Anchor Links to Clipboard */
117+
document.querySelectorAll('a.anchor').forEach(anchor => {
118+
anchor.addEventListener('click', function(e) {
119+
// We do NOT prevent default, so the browser still scrolls to the header naturally
120+
121+
// Construct the full absolute URL for the clipboard
122+
const fullUrl = window.location.origin + window.location.pathname + window.location.search + this.getAttribute('href');
123+
124+
// Use native clipboard API
125+
navigator.clipboard.writeText(fullUrl).then(() => {
126+
// Add the 'copied' class for visual feedback
127+
this.classList.add('copied');
128+
129+
// Remove the checkmark after 2 seconds
130+
setTimeout(() => {
131+
this.classList.remove('copied');
132+
}, 2000);
133+
}).catch(err => console.error('Failed to copy anchor:', err));
134+
});
135+
});
136+
/** 6. Hamburger Menu */
137+
document.addEventListener('DOMContentLoaded', function() {
138+
const menuToggle = document.getElementById('menu-toggle');
139+
140+
// Try to find the Toc (Table of Contents) or the Navigation Container
141+
const sidebar = document.getElementById('toc') ||
142+
document.querySelector('.nav-container') ||
143+
document.getElementById('sidebar');
144+
145+
if (menuToggle && sidebar) {
146+
menuToggle.addEventListener('click', function() {
147+
sidebar.classList.toggle('active');
148+
menuToggle.classList.toggle('open');
149+
150+
// Optional: Prevent body scrolling when menu is open
151+
document.body.classList.toggle('menu-open');
152+
});
153+
} else {
154+
console.warn("Hamburger menu: Could not find the navigation element to toggle.");
155+
}
156+
});
38157
</script>

docs/asciidoc/docinfo-header.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<div class="mobile-nav-bar">
2+
<span style="font-weight: 700; color: var(--heading-color);">Jooby</span>
3+
<button id="menu-toggle" class="hamburger" aria-label="Toggle Menu">
4+
<span></span><span></span><span></span>
5+
</button>
6+
</div>

docs/asciidoc/docinfo.html

Lines changed: 12 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,12 @@
1-
<link rel="stylesheet" href="/js/styles/toc.css">
2-
<style>
3-
/** Tabs */
4-
.hidden {
5-
display: none;
6-
}
7-
8-
.switch {
9-
display: inline-block;
10-
}
11-
12-
.switch--item {
13-
padding: 5px 10px;
14-
color: #fff;
15-
display: inline-block;
16-
cursor: pointer;
17-
background-color: #333;
18-
border-left: 1px solid #ffa;
19-
}
20-
21-
.switch--item:not(:first-child) {
22-
}
23-
24-
.switch--item:last-child {
25-
border-radius: 0 5px 0 0;
26-
}
27-
28-
.switch--item.selected {
29-
color: #ffa;
30-
border-bottom: 1px solid #ffa;
31-
}
32-
33-
.clipboard {
34-
position: absolute;
35-
bottom: .1rem;
36-
right: .1rem;
37-
display: inline-block;
38-
padding: 4px 8px;
39-
font-size: 13px;
40-
font-weight: 700;
41-
line-height: 20px;
42-
color: #333;
43-
white-space: nowrap;
44-
vertical-align: middle;
45-
cursor: pointer;
46-
background-color: #eee;
47-
background-image: linear-gradient(#fcfcfc, #eee);
48-
border: 1px solid #d5d5d5;
49-
border-radius: 3px;
50-
-webkit-user-select: none;
51-
-moz-user-select: none;
52-
-ms-user-select: none;
53-
user-select: none;
54-
-webkit-appearance: none
55-
}
56-
57-
.clipboard i {
58-
font-style: normal;
59-
font-weight: 500;
60-
opacity: .6
61-
}
62-
63-
.clipboard .octicon {
64-
vertical-align: text-top
65-
}
66-
67-
.clipboard .counter {
68-
text-shadow: none;
69-
background-color: #e5e5e5
70-
}
71-
72-
.clipboard:focus {
73-
text-decoration: none;
74-
border-color: #51a7e8;
75-
outline: none;
76-
box-shadow: 0 0 5px rgba(81, 167, 232, .5)
77-
}
78-
79-
.clipboard:focus:hover, .clipboard.selected:focus {
80-
border-color: #51a7e8
81-
}
82-
83-
.clipboard:hover, .clipboard:active, .clipboard.zeroclipboard-is-hover, .clipboard.zeroclipboard-is-active {
84-
text-decoration: none;
85-
background-color: #ddd;
86-
background-image: linear-gradient(#eee, #ddd);
87-
border-color: #ccc
88-
}
89-
90-
.clipboard:active, .clipboard.selected, .clipboard.zeroclipboard-is-active {
91-
background-color: #dcdcdc;
92-
background-image: none;
93-
border-color: #b5b5b5;
94-
box-shadow: inset 0 2px 4px rgba(0, 0, 0, .15)
95-
}
96-
97-
.clipboard.selected:hover {
98-
background-color: #cfcfcf
99-
}
100-
101-
.clipboard:disabled, .clipboard:disabled:hover, .clipboard.disabled, .clipboard.disabled:hover {
102-
color: rgba(102, 102, 102, .5);
103-
cursor: default;
104-
background-color: rgba(229, 229, 229, .5);
105-
background-image: none;
106-
border-color: rgba(197, 197, 197, .5);
107-
box-shadow: none
108-
}
109-
</style>
1+
<link rel="preconnect" href="https://fonts.googleapis.com">
2+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
3+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
4+
<script>
5+
// This MUST be in the <head>. It runs before the body is rendered, preventing the white flash.
6+
(function() {
7+
const savedTheme = localStorage.getItem('jooby-theme');
8+
if (savedTheme === 'dark' || (!savedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
9+
document.documentElement.setAttribute('data-theme', 'dark');
10+
}
11+
})();
12+
</script>

docs/asciidoc/ecosystem.adoc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
== Ecosystem
2+
[.lead]
3+
Extend the power of Jooby through its rich ecosystem of modules and standards. Learn how to seamlessly integrate with OpenAPI 3 to automatically generate interactive documentation and client SDKs, and explore a wide array of community and first-party modules that bring database access, security, and messaging to your application with minimal configuration.
24

35
The Jooby ecosystem is built on three core, interconnected concepts:
46

@@ -131,7 +133,7 @@ public class MyExtension implements Extension {
131133
public void install(Jooby app) {
132134
DataSource dataSource = createDataSource(); // <1>
133135
134-
app.getServices().put(DataSource.class, dataSource); // <2>
136+
app.getServices().put(DataSource.class, dataSource);// <2>
135137
136138
app.onStop(dataSource::close); // <3>
137139
}
@@ -150,11 +152,11 @@ import io.jooby.Jooby
150152
151153
class MyExtension : Extension {
152154
override fun install(app: Jooby) {
153-
val dataSource = createDataSource() // <1>
155+
val dataSource = createDataSource() // <1>
154156
155-
app.services.put(DataSource::class.java, dataSource) // <2>
157+
app.services.put(DataSource::class.java, dataSource) // <2>
156158
157-
app.onStop(dataSource::close) // <3>
159+
app.onStop(dataSource::close) // <3>
158160
}
159161
160162
private fun createDataSource(): DataSource {

docs/asciidoc/migration/3.x.adoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ Kotlin was removed from core, you need to the `jooby-kotlin` dependency:
6464
|===
6565

6666
==== Class renames
67+
[cols="1,1,2"]
6768
|===
6869
|2.x|3.x|Module
69-
|io.jooby.Route.Decorator|io.jooby.Route.Filter| jooby (core)
70+
|io.jooby.Route.Decorator| jooby (core) |io.jooby.Route.Filter
7071
|io.jooby.Kooby|io.jooby.kt.Kooby| jooby-kotlin (new module)
7172
|io.jooby.jetty.Jetty|io.jooby.jetty.JettyServer| jooby-jetty
7273
|io.jooby.netty.Netty|io.jooby.netty.NettyServer| jooby-netty
@@ -87,6 +88,7 @@ Kotlin was removed from core, you need to the `jooby-kotlin` dependency:
8788
|===
8889

8990
==== Method renames
91+
[cols="1,1,2"]
9092
|===
9193
|2.x|3.x|Description
9294
|Router.decorator(Decorator)|Router.use(Filter)| `decorator` has been deprecated in favor of `use`

docs/asciidoc/migration/4.x.adoc

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,20 @@ runApp(args, new NettyServer(new ServerOptions()), App::new);
6565
|===
6666

6767
==== Classes
68+
[cols="1,1,1,4"]
6869
|===
69-
|3.x|4.x|Description|Module
70-
|io.jooby.buffer.*|-| removed | jooby (core)
71-
||io.jooby.output.*| new output API | jooby (core)
72-
|io.jooby.MvcFactory|-| was deprecated and now removed | jooby (core)
73-
|io.jooby.annotation.ResultType|-| removed | jooby (core)
74-
|io.jooby.ValueNode|io.jooby.value.Value| replaced/merged | jooby (core)
75-
|io.jooby.ValueNodeConverter|io.jooby.value.ValueConverter| replaced/merged | jooby (core)
76-
|io.jooby.RouteSet|io.jooby.Route.Set| moved into Route and renamed to Set | jooby (core)
70+
|3.x|4.x|Module|Description
71+
|io.jooby.buffer.*|-| jooby (core) | removed
72+
||io.jooby.output.*| jooby (core) | new output API
73+
|io.jooby.MvcFactory|-| jooby (core) | was deprecated and now removed
74+
|io.jooby.annotation.ResultType|-| jooby (core) | removed
75+
|io.jooby.ValueNode|io.jooby.value.Value | jooby (core) | replaced/merged
76+
|io.jooby.ValueNodeConverter|io.jooby.value.ValueConverter| jooby (core) | replaced/merged
77+
|io.jooby.RouteSet|io.jooby.Route.Set | jooby (core) | moved into Route and renamed to Set
7778
|===
7879

7980
==== Method
81+
[cols="1,1,2"]
8082
|===
8183
|3.x|4.x|Description
8284
|io.jooby.Jooby.setServerOptions()|Server.setOptions()| removed in favor of `Server.setOptions()`

docs/asciidoc/modules/avaje-inject.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Please note that the order of annotation processors is important. For example, i
5757
public class App extends Jooby {
5858
5959
{
60-
install(AvajeInjectModule.of()); <1>
60+
install(AvajeInjectModule.of()); <1>
6161
6262
get("/", ctx -> {
6363
MyService service = require(MyService.class); <2>

0 commit comments

Comments
 (0)