Skip to content

Commit 550eb9a

Browse files
Refactor documentation and improve sign-in link relocation logic
1 parent 781e2b9 commit 550eb9a

4 files changed

Lines changed: 121 additions & 24 deletions

File tree

docs/.vitepress/theme/components/Card.vue

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ const props = defineProps({
1515
cta: String,
1616
});
1717
18-
const resolvedHref = computed(() => props.link || props.href || "#");
18+
const hasDestination = computed(() => Boolean((props.link || props.href || "").toString().trim()));
19+
20+
const resolvedHref = computed(() => {
21+
const h = (props.link || props.href || "").toString().trim();
22+
return h;
23+
});
1924
2025
// Custom SVG icons for brands
2126
const customSvgIcons = {
@@ -53,8 +58,9 @@ const IconComponent = computed(() => {
5358
</script>
5459

5560
<template>
56-
<a
57-
:href="resolvedHref"
61+
<component
62+
:is="hasDestination ? 'a' : 'div'"
63+
:href="hasDestination ? resolvedHref : undefined"
5864
class="card-link"
5965
:class="{ 'card-link--with-cta': cta }"
6066
>
@@ -72,5 +78,5 @@ const IconComponent = computed(() => {
7278
<slot />
7379
</p>
7480
<span v-if="cta" class="card-cta">{{ cta }} →</span>
75-
</a>
81+
</component>
7682
</template>

docs/.vitepress/theme/index.ts

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Theme } from "vitepress";
22
import type { ThemeContext } from "@voidzero-dev/vitepress-theme";
33
import VoidZeroTheme from "@voidzero-dev/vitepress-theme";
44
import { themeContextKey } from "@voidzero-dev/vitepress-theme";
5-
import { onMounted, watch, nextTick } from "vue";
5+
import { onMounted, onUnmounted, watch, nextTick } from "vue";
66
import { useRoute } from "vitepress";
77
import { enhanceAppWithTabs } from "vitepress-plugin-tabs/client";
88
import mediumZoom from "medium-zoom";
@@ -93,45 +93,101 @@ function updateHashOnTabClick(event: Event) {
9393
/**
9494
* Move "Sign in" CTA to the right utility area (between search and theme toggle).
9595
* The upstream OSSHeader renders nav links on the left; we remap only this CTA.
96+
* Returns true if the link was found and moved (or already in the target region).
9697
*/
97-
function moveSignInToUtilityArea() {
98-
if (typeof document === "undefined") return;
98+
function moveSignInToUtilityArea(): boolean {
99+
if (typeof document === "undefined") return false;
99100

100101
const signInLink = document.querySelector(
101-
'.docs-layout header .VPNavBarMenu a.VPLink[href*="sign-in"]',
102+
'.docs-layout header a.VPLink[href*="sign-in"]',
102103
) as HTMLAnchorElement | null;
103-
if (!signInLink) return;
104+
if (!signInLink) return false;
105+
106+
if (signInLink.classList.contains("sign-in-relocated")) {
107+
return true;
108+
}
104109

105110
const appearanceToggle = document.querySelector(
106111
".docs-layout header .VPNavBarAppearance",
107112
) as HTMLElement | null;
108113

114+
if (
115+
appearanceToggle?.parentElement &&
116+
signInLink.parentElement === appearanceToggle.parentElement
117+
) {
118+
signInLink.classList.add("sign-in-relocated");
119+
return true;
120+
}
121+
122+
const extraMenu = document.querySelector(
123+
".docs-layout header .VPNavBarExtra",
124+
) as HTMLElement | null;
125+
if (extraMenu?.parentElement && signInLink.parentElement === extraMenu.parentElement) {
126+
signInLink.classList.add("sign-in-relocated");
127+
return true;
128+
}
129+
109130
// Desktop (xl+): insert before theme toggle inside the utilities row.
110131
if (
111132
appearanceToggle?.parentElement &&
112133
signInLink.parentElement !== appearanceToggle.parentElement
113134
) {
114135
signInLink.classList.add("sign-in-relocated");
115136
appearanceToggle.parentElement.insertBefore(signInLink, appearanceToggle);
116-
return;
137+
return true;
117138
}
118139

119140
// Tablet fallback (lg-xl): keep it in right controls row before the extra menu.
120-
const extraMenu = document.querySelector(
121-
".docs-layout header .VPNavBarExtra",
122-
) as HTMLElement | null;
123141
if (extraMenu?.parentElement && signInLink.parentElement !== extraMenu.parentElement) {
124142
signInLink.classList.add("sign-in-relocated");
125143
extraMenu.parentElement.insertBefore(signInLink, extraMenu);
144+
return true;
126145
}
146+
147+
return false;
148+
}
149+
150+
let signInRelocateWarned = false;
151+
152+
function runSignInRelocationWithRetries() {
153+
if (typeof document === "undefined" || !document.querySelector(".docs-layout")) {
154+
return;
155+
}
156+
157+
const tryOnce = (attempt: number) => {
158+
if (moveSignInToUtilityArea()) {
159+
return;
160+
}
161+
if (attempt < 40) {
162+
window.setTimeout(() => tryOnce(attempt + 1), 75);
163+
} else if (!signInRelocateWarned) {
164+
const link = document.querySelector('.docs-layout header a.VPLink[href*="sign-in"]');
165+
if (link && !link.classList.contains("sign-in-relocated")) {
166+
signInRelocateWarned = true;
167+
console.warn(
168+
"[plane-docs] Sign-in could not be relocated (header not ready or selectors changed).",
169+
);
170+
}
171+
}
172+
};
173+
174+
tryOnce(0);
175+
}
176+
177+
function debounce(fn: () => void, ms: number) {
178+
let t: ReturnType<typeof setTimeout> | undefined;
179+
return () => {
180+
if (t) clearTimeout(t);
181+
t = setTimeout(fn, ms);
182+
};
127183
}
128184

129185
export default {
130186
extends: VoidZeroTheme,
131187
Layout,
132188
enhanceApp(ctx) {
189+
VoidZeroTheme.enhanceApp?.(ctx);
133190
ctx.app.provide(themeContextKey, planeThemeContext);
134-
VoidZeroTheme.enhanceApp(ctx);
135191
enhanceAppWithTabs(ctx.app);
136192
ctx.app.component("Card", Card);
137193
ctx.app.component("CardGroup", CardGroup);
@@ -146,20 +202,59 @@ export default {
146202
background: "rgba(0, 0, 0, 0.8)",
147203
});
148204

205+
let headerObserver: MutationObserver | null = null;
206+
let onResize: (() => void) | null = null;
207+
149208
onMounted(() => {
150209
// Delay tab hash handling to ensure tabs are rendered
151210
setTimeout(() => {
152211
handleTabHash();
153212
setupTabHashUpdates();
154-
moveSignInToUtilityArea();
213+
runSignInRelocationWithRetries();
214+
}, 100);
215+
216+
const onHeaderMutations = debounce(() => {
217+
runSignInRelocationWithRetries();
155218
}, 100);
156219

220+
const tryAttachHeaderObserver = () => {
221+
if (headerObserver) return;
222+
const h = document.querySelector(".docs-layout header");
223+
if (!h) return;
224+
headerObserver = new MutationObserver(onHeaderMutations);
225+
headerObserver.observe(h, { childList: true, subtree: true });
226+
};
227+
tryAttachHeaderObserver();
228+
if (!headerObserver) {
229+
const id = window.setInterval(() => {
230+
tryAttachHeaderObserver();
231+
if (headerObserver) {
232+
clearInterval(id);
233+
}
234+
}, 120);
235+
window.setTimeout(() => clearInterval(id), 5000);
236+
}
237+
238+
onResize = debounce(() => {
239+
runSignInRelocationWithRetries();
240+
}, 150);
241+
window.addEventListener("resize", onResize);
242+
157243
// Listen for hash changes
158244
window.addEventListener("hashchange", () => {
159245
nextTick(handleTabHash);
160246
});
161247
});
162248

249+
onUnmounted(() => {
250+
headerObserver?.disconnect();
251+
headerObserver = null;
252+
if (onResize) {
253+
window.removeEventListener("resize", onResize);
254+
onResize = null;
255+
}
256+
});
257+
163258
// Watch for route changes
164259
watch(
165260
() => route.path,
@@ -169,7 +264,7 @@ export default {
169264
zoom.attach(":not(a) > img:not(.VPImage)");
170265
handleTabHash();
171266
setupTabHashUpdates();
172-
moveSignInToUtilityArea();
267+
runSignInRelocationWithRetries();
173268
});
174269
},
175270
);

docs/.vitepress/theme/style.css

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ div[class*="language-"] > span.lang {
609609
color: #0a0a0a;
610610
}
611611

612-
.vp-doc .home-feature-cards .card-icon :deep(svg) {
612+
.vp-doc .home-feature-cards .card-icon svg {
613613
width: 24px;
614614
height: 24px;
615615
flex-shrink: 0;
@@ -746,12 +746,6 @@ div[class*="language-"] > span.lang {
746746
transform 0.2s ease !important;
747747
}
748748

749-
/* Prevent first-paint flash in left nav before JS relocates Sign in. */
750-
.docs-layout header .VPLink[href*="sign-in"]:not(.sign-in-relocated) {
751-
opacity: 0 !important;
752-
pointer-events: none !important;
753-
}
754-
755749
.docs-layout header a.VPLink[href*="sign-in"] .vp-external-link-icon {
756750
display: none !important;
757751
}

docs/index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ description:
88

99
<!-- @format -->
1010

11-
# Plane Documentation Plan, track, and ship your work with Plane.
11+
# Plane documentation
12+
13+
Plan, track, and ship your work with Plane.
1214

1315
This documentation helps you learn Plane, manage projects, collaborate with
1416
teams, and automate workflows.

0 commit comments

Comments
 (0)