Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions customHttp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ customHeaders:
'sha256-7eCV4jtsr4t4knb3c4FCRPeu7GGZeOUGE3XvWix0XOQ='
'sha256-OizSKqsU+f0G4vojbxNt0Lao3kUpTmCLQSv3y6P7qhQ='
'sha256-ZOND5PirXJ/KGOiJVbRQAIskp9o83/I3ySoXkGfvuec='
'sha256-vRP3yttWg1O/UPabV81Vjc2PIQisZEhROAiBTgxXmbM=' 'self'
'sha256-vRP3yttWg1O/UPabV81Vjc2PIQisZEhROAiBTgxXmbM='
'sha256-7HDSC8Js7nXYmgQNmtKTPjD+zSyeejuBySTNLmNHBEA=' 'self'
widgets.kinde.com kinde.com
https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.23.5/dist/browser/standalone.min.js
- key: Strict-Transport-Security
Expand Down Expand Up @@ -67,8 +68,9 @@ customHeaders:
https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.23.5/dist/browser/standalone.min.js
'unsafe-inline' 'self' widgets.kinde.com kinde.com; font-src
https://fonts.scalar.com 'self'; connect-src 'self' ws
GNCD7Z22NL-dsn.algolia.net https://api.hsforms.com
https://app.kinde.com https://kinde.com https://api-spec.kinde.com
https://api.management.inkeep.com https://api.inkeep.com
wss://api.inkeep.com https://api.hsforms.com https://app.kinde.com
https://kinde.com https://api-spec.kinde.com
https://kinde-api-docs-proxy.pages.dev;
- pattern: /kinde-apis/frontend/*
headers:
Expand Down
12,693 changes: 9,065 additions & 3,628 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@astrojs/tailwind": "^5.1.2",
"@docsearch/js": "^3.8.0",
"@fontsource/inter": "^5.1.0",
"@inkeep/uikit-js": "^0.3.19",
"astro": "^4.16.16",
"astro-auto-import": "^0.4.4",
"astro-icon": "^1.1.4",
Expand Down
24 changes: 24 additions & 0 deletions public/vendors/inkeep.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[data-theme="dark"] .ikp-modal__backdrop {
background: rgba(0,0,0,0.8);
}

[data-theme="light"] .ikp-modal__backdrop {
background: rgba(0,0,0,0.4);
}

.ikp-modal-widget__content {
opacity: 0;
animation: showInkeepModal .4s ease forwards;
}

@keyframes showInkeepModal {
from {
opacity: 0;
transform: scale(.975) translateY(5%);

}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
96 changes: 0 additions & 96 deletions src/components/DocSearch.astro

This file was deleted.

144 changes: 144 additions & 0 deletions src/components/Inkeep.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<script>
// Get the button element
const inkeepTriggers = document.querySelectorAll("[kui-trigger='search']");

// Create a new div element to hold the Inkeep modal and set its id and position
const inkeepDiv = document.createElement("div");
inkeepDiv.id = "inkeepModal";
inkeepDiv.style.position = "absolute";
document.body.appendChild(inkeepDiv);

const handleClose = () => {
inkeepWidget.render({
...config,
isOpen: false,
baseSettings: undefined
});
};

const handleOpen = () => {
const theme = document.documentElement.getAttribute("data-theme");
const isInkeepActive = document.body.classList.contains("inkeep-active");

if (isInkeepActive) {
inkeepWidget.render({
...config,
isOpen: true,
baseSettings: {
colorMode: {
forcedColorMode: theme
}
}
});
} else {
initializeInkeep();
}
};

const config = {
componentType: "CustomTrigger", // required
targetElement: inkeepDiv, // required
properties: {
isOpen: false, // required
onClose: handleClose, // required
onOpen: undefined,
baseSettings: {
apiKey: import.meta.env.PUBLIC_INKEEP_API_KEY!, // required
integrationId: import.meta.env.PUBLIC_INKEEP_INTEGRATION_ID!, // required
organizationId: import.meta.env.PUBLIC_INKEEP_ORGANIZATION_ID!, // required
Comment on lines +46 to +48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Secure handling of API keys needed.

The API keys are exposed in the client-side code. Consider:

  1. Moving these to server-side environment variables
  2. Implementing token rotation if possible
  3. Adding API key restrictions in Inkeep dashboard

primaryBrandColor: "#0f0f0f",
organizationDisplayName: "Kinde",
colorMode: {
enableSystem: true
},
theme: {
stylesheetUrls: ["/vendors/inkeep.css"]
}
},
aiChatSettings: {
chatSubjectName: "Kinde",
botAvatarSrcUrl:
"https://storage.googleapis.com/organization-image-assets/kinde-botAvatarSrcUrl-1720166731622.png",
botAvatarDarkSrcUrl:
"https://storage.googleapis.com/organization-image-assets/kinde-botAvatarDarkSrcUrl-1720676197273.png",
getHelpCallToActions: [
{
name: "Slack",
url: "https://join.slack.com/t/thekindecommunity/shared_invite/zt-2k5i0aeet-d6Z_2qYphcNCpj0bFa4oCg",
icon: {
builtIn: "FaSlack"
}
},
{
name: "Discord",
url: "https://discord.gg/wHX6j7wG5d",
icon: {
builtIn: "FaDiscord"
}
},
{
name: "Github",
url: "https://github.com/kinde-oss",
icon: {
builtIn: "FaGithub"
}
}
],
quickQuestions: [
"Where do I set up my authentication methods?",
"How can I be notified when certain events happen?",
"What's the quickest way to get started with Kinde?"
]
}
}
};

// Embed the widget using the `Inkeep.embed()` function.
let inkeepWidget: any;
// Add event listener to open the Inkeep modal when the button is clicked
inkeepTriggers.forEach((trigger) => trigger.addEventListener("click", handleOpen));

function initializeInkeep() {
import("@inkeep/uikit-js/dist/embed.js")
.then((lib) => {
inkeepWidget = lib.Inkeep(config.properties.baseSettings).embed(config as any); //

document.body.classList.add("inkeep-active");
})
.then(() => {
const theme = document.documentElement.getAttribute("data-theme");

inkeepWidget.render({
...config,
isOpen: true,
baseSettings: {
colorMode: {
forcedColorMode: theme
}
}
});
})
.catch((error) => console.log(error));
}
Comment on lines +101 to +122
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling in initialization.

The error handling is minimal with just console.log. Consider:

-          .catch((error) => console.log(error));
+          .catch((error) => {
+              console.error('Failed to initialize Inkeep:', error);
+              // Fallback to a basic search or show user-friendly error
+              document.body.classList.remove("inkeep-active");
+          });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function initializeInkeep() {
import("@inkeep/uikit-js/dist/embed.js")
.then((lib) => {
inkeepWidget = lib.Inkeep(config.properties.baseSettings).embed(config as any); //
document.body.classList.add("inkeep-active");
})
.then(() => {
const theme = document.documentElement.getAttribute("data-theme");
inkeepWidget.render({
...config,
isOpen: true,
baseSettings: {
colorMode: {
forcedColorMode: theme
}
}
});
})
.catch((error) => console.log(error));
}
function initializeInkeep() {
import("@inkeep/uikit-js/dist/embed.js")
.then((lib) => {
inkeepWidget = lib.Inkeep(config.properties.baseSettings).embed(config as any); //
document.body.classList.add("inkeep-active");
})
.then(() => {
const theme = document.documentElement.getAttribute("data-theme");
inkeepWidget.render({
...config,
isOpen: true,
baseSettings: {
colorMode: {
forcedColorMode: theme
}
}
});
})
.catch((error) => {
console.error('Failed to initialize Inkeep:', error);
// Fallback to a basic search or show user-friendly error
document.body.classList.remove("inkeep-active");
});
}


document.addEventListener("keydown", function (event) {
// Check if the `/` key is pressed
if (event.key === "/" && !event.metaKey && !event.ctrlKey) {
event.preventDefault();
handleOpen();
}

// Check if Cmd (Meta) + K or Ctrl + K is pressed
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
event.preventDefault();
handleOpen();
}
});
</script>


<style is:inline>
[data-theme="dark"] .ikp-modal__container {
filter: invert(0);
}
</style>
14 changes: 6 additions & 8 deletions src/starlight-overrides/Footer.astro
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
import Default from "@astrojs/starlight/components/Footer.astro";
import type {Props} from "@astrojs/starlight/props";
import type { Props } from "@astrojs/starlight/props";
import ArticleFeedback from "@components/ArticleFeedback.astro";
import DocSearch from "@components/DocSearch.astro";
import FooterCards from "@components/FooterCards.astro";
import ImageZoom from "@components/ImageZoom.astro";
import RelatedArticles, {type RelatedArticle} from "@components/RelatedArticles.astro";
import {getCollection} from "astro:content";
import Inkeep from "@components/Inkeep.astro";
import RelatedArticles, { type RelatedArticle } from "@components/RelatedArticles.astro";
import { getCollection } from "astro:content";
const {entry} = Astro.props;

let relatedArticles: RelatedArticle[] = [];
Expand Down Expand Up @@ -69,15 +69,13 @@ if (entry.data.relatedArticles) {
)
}

<DocSearch />
<Inkeep />

<script is:inline>
// This will make sure the current page link in the right sidebar will be in view even when the navigation started via a search result link or a referrer other than the docs. It will also ensure that the main topic details element is open.

const isReferredFromAlgolia = window.location.href.includes("?r=search");
const isReferredFromInternalLink = document.referrer.includes(window.location.origin);

if (isReferredFromAlgolia || !isReferredFromInternalLink) {
if (!isReferredFromInternalLink) {
const currentLinkMainTopicDetailsEl = document.querySelector(
'#starlight__sidebar details:has(a[aria-current="page"])'
);
Expand Down
6 changes: 0 additions & 6 deletions src/starlight-overrides/Head.astro
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,3 @@ const hasCustomOGImage = Astro.props.entry.data.head.find((t) =>
</Default>

{!hasCustomOGImage && <meta property="og:image" content={`${Astro.url.href}og-image.png`} />}

<link
rel="preconnect"
href=`https://${import.meta.env.PUBLIC_ALGOLIA_APP_ID}-dsn.algolia.net`
crossorigin
/>
2 changes: 1 addition & 1 deletion src/starlight-overrides/Search.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ import {Icon} from "astro-icon/components";
>
<Icon name="search" size={20} class="stroke-2 lg:stroke-1" />
<span class="hidden leading-[1] text-kinde-grey-700 lg:block dark:text-white">Search docs</span>
</button>
</button>
8 changes: 2 additions & 6 deletions src/styles/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,8 @@ button[aria-controls="starlight__sidebar"] svg {
transform: scale(1.5);
}

body.DocSearch--active .c-help-widget,
body.DocSearch--active header .header {
padding-right: 15px;
}

body.DocSearch--active .main-frame {
body[data-inert] .c-help-widget,
body[data-inert] header .header {
padding-right: 15px;
}

Expand Down
Loading
Loading