coherent-docs-theme 1.0.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.
Files changed (40) hide show
  1. package/README.md +314 -0
  2. package/assets/gameface-ui-header-dark.svg +5 -0
  3. package/assets/gameface-ui-header-light.svg +5 -0
  4. package/components/Api.astro +29 -0
  5. package/components/BeforeAfter.astro +124 -0
  6. package/components/Details.astro +37 -0
  7. package/components/Enhancement.astro +29 -0
  8. package/components/Feature.astro +29 -0
  9. package/components/Figure.astro +107 -0
  10. package/components/Fix.astro +29 -0
  11. package/components/GallerySlider.astro +260 -0
  12. package/components/If.astro +6 -0
  13. package/components/IfEnv.astro +5 -0
  14. package/components/IfNot.astro +6 -0
  15. package/components/IncludeSnippets.astro +13 -0
  16. package/components/Internal.astro +3 -0
  17. package/components/ProductName.astro +13 -0
  18. package/components/Release.astro +68 -0
  19. package/components/SideBarWithDropdown.astro +8 -0
  20. package/components/Typeref.astro +35 -0
  21. package/index.ts +152 -0
  22. package/internal/overrideComponents.ts +29 -0
  23. package/internal/themeConfig.ts +21 -0
  24. package/internal-components/ChangelogRow.astro +39 -0
  25. package/internal-components/NavLinks.astro +253 -0
  26. package/internal-components/ProgressIndicator.astro +53 -0
  27. package/overrides/Footer.astro +103 -0
  28. package/overrides/Header.astro +91 -0
  29. package/overrides/Search.astro +234 -0
  30. package/overrides/ThemeSelect.astro +218 -0
  31. package/package.json +46 -0
  32. package/remark-directives/if.ts +51 -0
  33. package/remark-directives/includeSnippets.ts +120 -0
  34. package/remark-directives/index.ts +13 -0
  35. package/remark-directives/internal.ts +20 -0
  36. package/remark-directives/release.ts +29 -0
  37. package/styles.css +452 -0
  38. package/utils/changelogSideBar.ts +105 -0
  39. package/utils/changelogSideBarMultipleDocs.ts +119 -0
  40. package/utils/coherentReleases.ts +62 -0
@@ -0,0 +1,39 @@
1
+ ---
2
+ import { Badge } from "@astrojs/starlight/components";
3
+ export interface ChangelogProps {
4
+ engine?: "Unreal Engine" | "Unity" | "Native" | undefined;
5
+ description?: string | undefined;
6
+ }
7
+
8
+ interface Props extends ChangelogProps {
9
+ badgeText: string;
10
+ badgeVariant: "note" | "danger" | "success" | "caution" | "tip" | "default";
11
+ }
12
+
13
+ const { badgeText, badgeVariant, engine, description } = Astro.props;
14
+
15
+ const allowedEngines = ["Unreal Engine", "Unity", "Native"];
16
+
17
+ if (engine && !allowedEngines.includes(engine)) {
18
+ throw new Error(
19
+ `[ChangelogRow] Invalid engine "${engine}". Allowed: ${allowedEngines.join(", ")}`,
20
+ );
21
+ }
22
+ ---
23
+
24
+ <tr>
25
+ <td>
26
+ <Badge text={badgeText} variant={badgeVariant} size="medium" />
27
+
28
+ {engine && <Badge text={engine} variant="tip" size="medium" />}
29
+ </td>
30
+ <td>
31
+ {Astro.slots.has("default") ? <slot /> : <span>{description}</span>}
32
+ </td>
33
+ </tr>
34
+
35
+ <style>
36
+ td :global(.sl-badge) {
37
+ margin-right: 0.5rem;
38
+ }
39
+ </style>
@@ -0,0 +1,253 @@
1
+ ---
2
+ import getThemeConfig from "../internal/themeConfig";
3
+ import { Icon } from "@astrojs/starlight/components";
4
+
5
+ interface Props {
6
+ type?: "header" | "sidebar";
7
+ }
8
+
9
+ const { type = "header" } = Astro.props;
10
+ const { navLinks } = getThemeConfig();
11
+ const currentPath = Astro.url.pathname;
12
+
13
+ const isLinkActive = (href: string) => {
14
+ if (href === "/") return currentPath === "/";
15
+ return currentPath.startsWith(href);
16
+ };
17
+
18
+ const navClasses =
19
+ type === "header"
20
+ ? "extra-links sl-hidden md:sl-flex"
21
+ : "extra-links mobile sidebar-mode lg:hidden";
22
+
23
+ const activeLinkObj = navLinks?.find((link) => isLinkActive(link.href));
24
+ const activeLabel = activeLinkObj ? activeLinkObj.label : "Documentations";
25
+ ---
26
+
27
+ {
28
+ navLinks && navLinks.length > 0 && (
29
+ <>
30
+ <nav class={"smart-nav " + navClasses} id="smart-nav" aria-label="Global Navigation">
31
+ {type === "header" && (
32
+ <div class="vertical-separator md:sl-flex" />
33
+ )}
34
+
35
+ <ul class="full-nav-list">
36
+ {navLinks.map((link) => (
37
+ <li class="nav-item">
38
+ <a
39
+ href={link.href}
40
+ class={`nav-link ${isLinkActive(link.href) ? "active" : ""}`}
41
+ >
42
+ {link.label}
43
+ </a>
44
+ </li>
45
+ ))}
46
+ </ul>
47
+
48
+ <div class="collapsed-menu" style="display: none;">
49
+ <button class="dropdown-btn" aria-expanded="false">
50
+ <span class="btn-text">{activeLabel}</span>
51
+ <Icon name="down-caret" size="0.75rem" />
52
+ </button>
53
+
54
+ <ul class="dropdown-list">
55
+ {navLinks.map((link) => (
56
+ <li>
57
+ <a
58
+ href={link.href}
59
+ class={`dropdown-link ${isLinkActive(link.href) ? "active" : ""}`}
60
+ >
61
+ {link.label}
62
+ </a>
63
+ </li>
64
+ ))}
65
+ </ul>
66
+ </div>
67
+ </nav>
68
+ </>
69
+ )
70
+ }
71
+
72
+ <style>
73
+ .smart-nav {
74
+ width: 100%;
75
+ height: 100%;
76
+ display: flex;
77
+ align-items: center;
78
+ }
79
+
80
+ .vertical-separator {
81
+ width: 1px;
82
+ height: 1.5rem;
83
+ margin-right: 1rem;
84
+ background-color: var(--sl-color-gray-5);
85
+ }
86
+
87
+ .full-nav-list {
88
+ list-style: none;
89
+ padding: 0;
90
+ margin: 0;
91
+ display: flex;
92
+ gap: 1.5rem;
93
+ align-items: center;
94
+ white-space: nowrap;
95
+ }
96
+
97
+ .nav-link {
98
+ color: var(--sl-color-gray-3);
99
+ text-decoration: none;
100
+ font-size: 0.85rem;
101
+ font-weight: 700;
102
+ text-transform: uppercase;
103
+ display: block;
104
+ padding: 0.5rem 0;
105
+ transition: color 0.2s;
106
+ }
107
+
108
+ .nav-link:hover,
109
+ .nav-link.active {
110
+ color: var(--sl-color-white);
111
+ }
112
+ .nav-link.active {
113
+ color: var(--sl-color-accent);
114
+ }
115
+ .collapsed-menu {
116
+ position: relative;
117
+ }
118
+
119
+ .dropdown-btn {
120
+ background: transparent;
121
+ border: 1px solid var(--sl-color-gray-5);
122
+ color: var(--sl-color-gray-3);
123
+ cursor: pointer;
124
+ font-weight: 700;
125
+ font-size: 0.85rem;
126
+ text-transform: uppercase;
127
+ display: flex;
128
+ align-items: center;
129
+ gap: 0.5rem;
130
+ padding: 0.35rem 0.75rem;
131
+ border-radius: 4px;
132
+ white-space: nowrap;
133
+ }
134
+
135
+ .dropdown-btn:hover {
136
+ border-color: var(--sl-color-gray-2);
137
+ color: var(--sl-color-white);
138
+ }
139
+
140
+ .collapsed-menu.has-active .dropdown-btn {
141
+ color: var(--sl-color-accent);
142
+ border-color: var(--sl-color-accent);
143
+ background: rgba(var(--sl-color-accent-rgb), 0.1);
144
+ }
145
+
146
+ .dropdown-list {
147
+ position: absolute;
148
+ top: 100%;
149
+ left: 0;
150
+ background-color: var(--sl-color-bg-nav);
151
+ border: 1px solid var(--sl-color-gray-5);
152
+ border-radius: 0.5rem;
153
+ box-shadow: var(--sl-shadow-lg);
154
+ padding: 0.5rem 0;
155
+ list-style: none;
156
+ display: none;
157
+ flex-direction: column;
158
+ min-width: 200px;
159
+ z-index: 9999;
160
+ }
161
+ .collapsed-menu:hover .dropdown-list {
162
+ display: flex;
163
+ }
164
+
165
+ .dropdown-link {
166
+ display: block;
167
+ padding: 0.75rem 1.5rem;
168
+ color: var(--sl-color-gray-3);
169
+ text-decoration: none;
170
+ font-size: 0.9rem;
171
+ }
172
+
173
+ .dropdown-link:hover {
174
+ background-color: var(--sl-color-gray-6);
175
+ color: var(--sl-color-white);
176
+ }
177
+
178
+ .dropdown-link.active {
179
+ color: var(--sl-color-accent);
180
+ font-weight: bold;
181
+ }
182
+ </style>
183
+
184
+ <script>
185
+ class SmartNav {
186
+ container: HTMLElement;
187
+ verticalSeparator: HTMLElement | null;
188
+ fullList: HTMLElement;
189
+ collapsedMenu: HTMLElement;
190
+ fullListWidth: number;
191
+
192
+ constructor(navElement: HTMLElement) {
193
+ this.container = navElement;
194
+ this.verticalSeparator = navElement.querySelector(".vertical-separator") as HTMLElement;
195
+ this.fullList = navElement.querySelector(".full-nav-list") as HTMLElement;
196
+ this.collapsedMenu = navElement.querySelector(".collapsed-menu") as HTMLElement;
197
+
198
+ this.fullListWidth = this.calculateRequiredWidth();
199
+
200
+ if (this.fullList.querySelector(".active")) {
201
+ this.collapsedMenu.classList.add("has-active");
202
+ }
203
+
204
+ this.check();
205
+
206
+ const observer = new ResizeObserver(() => {
207
+ requestAnimationFrame(() => this.check());
208
+ });
209
+ observer.observe(this.container);
210
+ }
211
+
212
+ calculateRequiredWidth() {
213
+ const items = Array.from(this.fullList.children) as HTMLElement[];
214
+ if (items.length === 0) return 0;
215
+
216
+ let totalWidth = 0;
217
+ items.forEach((item) => {
218
+ totalWidth += item.getBoundingClientRect().width;
219
+ });
220
+
221
+ const gap = 24;
222
+ totalWidth += (items.length - 1) * gap;
223
+
224
+ return totalWidth + 10;
225
+ }
226
+
227
+ check() {
228
+ const availableWidth = this.container.getBoundingClientRect().width;
229
+
230
+ if (availableWidth === 0) return;
231
+
232
+ if (availableWidth < this.fullListWidth) {
233
+ if(this.verticalSeparator) this.verticalSeparator.style.display = "none";
234
+ this.container.style.flexDirection = "row-reverse";
235
+ this.fullList.style.display = "none";
236
+ this.collapsedMenu.style.display = "block";
237
+ } else {
238
+ if(this.verticalSeparator) this.verticalSeparator.style.display = "block";
239
+ this.container.style.flexDirection = "row";
240
+ this.fullList.style.display = "flex";
241
+ this.collapsedMenu.style.display = "none";
242
+ }
243
+ }
244
+ }
245
+
246
+ const init = () => {
247
+ const nav = document.getElementById("smart-nav");
248
+ if (nav) new SmartNav(nav);
249
+ };
250
+
251
+ document.addEventListener("astro:page-load", init);
252
+ document.addEventListener("DOMContentLoaded", init);
253
+ </script>
@@ -0,0 +1,53 @@
1
+ <div class="progress-scroll-container" aria-hidden="true">
2
+ <div id="progress-scroll"></div>
3
+ </div>
4
+
5
+ <script>
6
+ window.addEventListener("scroll", function () {
7
+ updateProgressScroll();
8
+ });
9
+ window.addEventListener("load", function () {
10
+ updateProgressScroll();
11
+ });
12
+
13
+ function updateProgressScroll() {
14
+ const progressScroll = document.getElementById("progress-scroll");
15
+ if (progressScroll) {
16
+ const scrollTop =
17
+ window.scrollY || document.documentElement.scrollTop;
18
+ const scrollHeight =
19
+ document.documentElement.scrollHeight - window.innerHeight;
20
+ if (scrollHeight > 0) {
21
+ const progress = (scrollTop / scrollHeight) * 100;
22
+ progressScroll.style.width = progress + "%";
23
+ } else {
24
+ progressScroll.style.width = "0%";
25
+ }
26
+ }
27
+ }
28
+ </script>
29
+
30
+ <style>
31
+ html:is(:not([data-has-hero]), [data-has-sidebar], [data-has-toc])
32
+ .progress-scroll-container {
33
+ position: fixed;
34
+ top: 0;
35
+ left: 0;
36
+ height: 0.25rem;
37
+ width: 100%;
38
+ background-color: transparent;
39
+ z-index: 3;
40
+ }
41
+
42
+ #progress-scroll {
43
+ height: 100%;
44
+ width: 0px;
45
+ background-color: var(--sl-color-accent);
46
+ }
47
+ </style>
48
+
49
+ <style is:global>
50
+ #starlight__on-this-page--mobile {
51
+ margin-top: 0.25rem;
52
+ }
53
+ </style>
@@ -0,0 +1,103 @@
1
+ ---
2
+ import type { Props } from "@astrojs/starlight/props";
3
+ import DefaultFooter from "@astrojs/starlight/components/Footer.astro";
4
+
5
+ const currentYear = new Date().getFullYear();
6
+
7
+ const { pagination, editUrl, lastUpdated } = (Astro.locals as any)
8
+ .starlightRoute;
9
+
10
+ const hasPagination = !!(pagination?.prev || pagination?.next);
11
+ const hasMeta = !!(editUrl || lastUpdated);
12
+ const hasAnyFooterContent = hasPagination || hasMeta;
13
+ ---
14
+
15
+ <footer
16
+ class:list={[
17
+ "sl-footer",
18
+ { "no-meta": !hasMeta },
19
+ { "no-pagination": !hasPagination },
20
+ { "has-any-content": hasAnyFooterContent },
21
+ ]}
22
+ >
23
+ {hasPagination && <hr class="footer-divider" />}
24
+
25
+ <DefaultFooter {...Astro.props}>
26
+ <slot />
27
+ </DefaultFooter>
28
+ </footer>
29
+
30
+ <div class="custom-copyright">
31
+ <p>
32
+ &copy; {currentYear}
33
+ <strong>Coherent Labs</strong>. All rights reserved.
34
+ </p>
35
+ <div class="links">
36
+ <a href="https://coherent-labs.com/privacy-policy" rel="noopener" target="_blank"
37
+ >Privacy Policy</a
38
+ >
39
+ </div>
40
+ </div>
41
+
42
+ <style>
43
+ .sl-footer {
44
+ margin-top: 0 !important;
45
+ }
46
+
47
+ .sl-footer.has-any-content {
48
+ margin-top: 3rem !important;
49
+ }
50
+
51
+ .sl-footer.no-meta :global(.meta) {
52
+ display: none !important;
53
+ }
54
+
55
+ .sl-footer.no-pagination :global(.pagination-links) {
56
+ display: none !important;
57
+ }
58
+
59
+ .sl-footer :global(.meta) {
60
+ margin-top: 0 !important;
61
+ padding-top: 0 !important;
62
+ }
63
+
64
+ .footer-divider {
65
+ border: 0;
66
+ border-top: 1px solid var(--sl-color-gray-5);
67
+ margin-bottom: 1.5rem;
68
+ opacity: 0.5;
69
+ }
70
+
71
+ .custom-copyright {
72
+ margin-top: 2rem;
73
+ padding-top: 2rem;
74
+ border-top: 1px solid var(--sl-color-hairline);
75
+ display: flex;
76
+ flex-direction: column;
77
+ align-items: center;
78
+ gap: 0.5rem;
79
+ text-align: center;
80
+ color: var(--sl-color-gray-3);
81
+ font-size: 0.85rem;
82
+ }
83
+
84
+ .custom-copyright strong {
85
+ color: var(--sl-color-white);
86
+ }
87
+
88
+ .links {
89
+ display: flex;
90
+ gap: 0.5rem;
91
+ align-items: center;
92
+ }
93
+
94
+ .links a {
95
+ color: var(--sl-color-gray-3);
96
+ text-decoration: none;
97
+ transition: color 0.2s;
98
+ }
99
+
100
+ .links a:hover {
101
+ color: var(--sl-color-accent);
102
+ }
103
+ </style>
@@ -0,0 +1,91 @@
1
+ ---
2
+ import config from "virtual:starlight/user-config";
3
+ import LanguageSelect from "@astrojs/starlight/components/LanguageSelect.astro";
4
+ import SiteTitle from "@astrojs/starlight/components/SiteTitle.astro";
5
+ import SocialIcons from "@astrojs/starlight/components/SocialIcons.astro";
6
+ import ThemeSelect from "./ThemeSelect.astro";
7
+ import ProgressIndicator from "../internal-components/ProgressIndicator.astro";
8
+ import getThemeConfig from "../internal/themeConfig";
9
+ import NavLinks from "../internal-components/NavLinks.astro";
10
+ import Search from "./Search.astro";
11
+
12
+ const { showPageProgress } = getThemeConfig();
13
+ const shouldRenderSearch =
14
+ config.pagefind ||
15
+ config.components.Search !== "@astrojs/starlight/components/Search.astro";
16
+ ---
17
+
18
+ {showPageProgress && <ProgressIndicator />}
19
+ <div class="header sl-flex">
20
+ <div class="left-group">
21
+ <div class="site-title-wrapper">
22
+ <SiteTitle />
23
+ </div>
24
+
25
+ <div class="nav-wrapper">
26
+ <NavLinks />
27
+ </div>
28
+ </div>
29
+
30
+ <div class="right-group print:hidden">
31
+ <div class="search-container">
32
+ {shouldRenderSearch && <Search />}
33
+ </div>
34
+ <div class="actions-wrapper sl-hidden md:sl-flex">
35
+ <SocialIcons />
36
+ <ThemeSelect />
37
+ <LanguageSelect />
38
+ </div>
39
+ </div>
40
+ </div>
41
+
42
+ <style>
43
+ .header {
44
+ gap: var(--sl-nav-gap);
45
+ justify-content: space-between;
46
+ align-items: center;
47
+ height: 100%;
48
+ width: 100%;
49
+ display: flex;
50
+ }
51
+
52
+ .left-group {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: 1.5rem;
56
+ flex: 1;
57
+ min-width: 0;
58
+ }
59
+
60
+ .site-title-wrapper {
61
+ flex-shrink: 0;
62
+ }
63
+
64
+ .nav-wrapper {
65
+ flex: 1;
66
+ min-width: 0;
67
+ display: flex;
68
+ justify-content: flex-start;
69
+ overflow: visible;
70
+ align-items: center;
71
+ }
72
+
73
+ .right-group {
74
+ display: flex;
75
+ align-items: center;
76
+ gap: 1rem;
77
+ flex-shrink: 0;
78
+ margin-left: auto;
79
+ }
80
+
81
+ .actions-wrapper {
82
+ align-items: center;
83
+ gap: 1rem;
84
+ }
85
+
86
+ .vertical-separator {
87
+ width: 1px;
88
+ height: 1.5rem;
89
+ background-color: var(--sl-color-gray-5);
90
+ }
91
+ </style>