@moldea.ai/website-ui 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.
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/cover.png +0 -0
- package/dist/chunks/exceptions-BYCwx4kO.js +20 -0
- package/dist/chunks/exceptions-BYCwx4kO.js.map +1 -0
- package/dist/exceptions.d.ts +9 -0
- package/dist/exceptions.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/search/index.d.ts +22 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search.js +66 -0
- package/dist/search.js.map +1 -0
- package/dist/site/index.d.ts +41 -0
- package/dist/site/index.d.ts.map +1 -0
- package/dist/site.js +54 -0
- package/dist/site.js.map +1 -0
- package/dist/theme/index.d.ts +15 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme.js +18 -0
- package/dist/theme.js.map +1 -0
- package/package.json +118 -0
- package/src/components/action-button/action-button.component.astro +25 -0
- package/src/components/action-link/action-link.component.astro +18 -0
- package/src/components/brand-logo/brand-logo.component.astro +55 -0
- package/src/components/breadcrumbs/breadcrumbs.component.astro +52 -0
- package/src/components/inline-brand-text/inline-brand-text.component.astro +20 -0
- package/src/components/local-search/local-search.component.astro +188 -0
- package/src/components/theme-bootstrap/theme-bootstrap.component.astro +32 -0
- package/src/components/theme-control/theme-control.component.astro +126 -0
- package/src/exceptions.ts +21 -0
- package/src/search/index.ts +118 -0
- package/src/site/index.ts +74 -0
- package/src/styles.css +248 -0
- package/src/theme/index.ts +19 -0
- package/src/tokens.css +155 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 moldea.ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# `@moldea.ai/website-ui`
|
|
2
|
+
|
|
3
|
+
Shared Astro foundations for moldea public websites.
|
|
4
|
+
|
|
5
|
+
The package owns the reusable design tokens, global website primitives, interaction states, base-path and theme utilities, and small accessible Astro components used by the package and skill websites. Each website continues to own its page composition, navigation copy, content generation, SEO identity, public assets, site URL, and theme storage key.
|
|
6
|
+
|
|
7
|
+
## Install after release
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @moldea.ai/website-ui@1.0.0
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The package currently supports Astro `7.2.2` and Tailwind CSS `4.3.3` exactly. Import the shared stylesheet once from the website's global stylesheet:
|
|
14
|
+
|
|
15
|
+
```css
|
|
16
|
+
@import '@moldea.ai/website-ui/styles.css';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Tailwind scans the shipped Astro components through the package stylesheet's explicit source declaration.
|
|
20
|
+
|
|
21
|
+
## Utilities
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { searchDocuments } from '@moldea.ai/website-ui/search';
|
|
25
|
+
import { withBase } from '@moldea.ai/website-ui/site';
|
|
26
|
+
import { isDarkTheme } from '@moldea.ai/website-ui/theme';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`parseSearchDocuments` accepts only complete search records with safe root-relative result URLs. Base-path failures and invalid generated search indexes throw `WebsiteUiConfigurationException` with stable error codes.
|
|
30
|
+
|
|
31
|
+
## Components
|
|
32
|
+
|
|
33
|
+
Every component has a dedicated public subpath:
|
|
34
|
+
|
|
35
|
+
- `@moldea.ai/website-ui/action-button`
|
|
36
|
+
- `@moldea.ai/website-ui/action-link`
|
|
37
|
+
- `@moldea.ai/website-ui/brand-logo`
|
|
38
|
+
- `@moldea.ai/website-ui/breadcrumbs`
|
|
39
|
+
- `@moldea.ai/website-ui/inline-brand-text`
|
|
40
|
+
- `@moldea.ai/website-ui/local-search`
|
|
41
|
+
- `@moldea.ai/website-ui/theme-bootstrap`
|
|
42
|
+
- `@moldea.ai/website-ui/theme-control`
|
|
43
|
+
|
|
44
|
+
`ThemeBootstrap` belongs in the document head before rendered content. Pass the same app-owned storage key to `ThemeControl`. `BrandLogo` receives app-owned asset paths and labels rather than embedding one site's identity. `LocalSearch` receives app-owned copy, routes, and the generated index URL.
|
|
45
|
+
|
|
46
|
+
## Development
|
|
47
|
+
|
|
48
|
+
From the monorepo root:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pnpm --filter @moldea.ai/website-ui typecheck
|
|
52
|
+
pnpm --filter @moldea.ai/website-ui build
|
|
53
|
+
pnpm --filter @moldea.ai/website-ui test:unit
|
|
54
|
+
pnpm --filter @moldea.ai/website-ui test:integration
|
|
55
|
+
pnpm --filter @moldea.ai/website-ui test
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The integration suite verifies the packed public surface and a real Astro consumer fixture. Publishing the package is a separate release operation and is not part of ordinary website development.
|
package/cover.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Exception } from "error-message-utils";
|
|
2
|
+
//#region src/exceptions.ts
|
|
3
|
+
var CONFIGURATION_ERROR_MESSAGES = {
|
|
4
|
+
INVALID_BASE_PATH: "The website base path contains unsupported URL characters.",
|
|
5
|
+
INVALID_SEARCH_INDEX: "The documentation search index is invalid."
|
|
6
|
+
};
|
|
7
|
+
/** Represents invalid configuration or generated input at a website UI boundary. */
|
|
8
|
+
var WebsiteUiConfigurationException = class extends Exception {
|
|
9
|
+
code;
|
|
10
|
+
/** Creates the stable configuration exception for one failed boundary. */
|
|
11
|
+
constructor(code) {
|
|
12
|
+
super(CONFIGURATION_ERROR_MESSAGES[code], code);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.name = "WebsiteUiConfigurationException";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { WebsiteUiConfigurationException as t };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=exceptions-BYCwx4kO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exceptions-BYCwx4kO.js","names":[],"sources":["../../src/exceptions.ts"],"sourcesContent":["import { Exception } from 'error-message-utils';\n\n// stable configuration failure contracts exposed by the package\nexport type IWebsiteUiConfigurationErrorCode = 'INVALID_BASE_PATH' | 'INVALID_SEARCH_INDEX';\n\nconst CONFIGURATION_ERROR_MESSAGES = {\n INVALID_BASE_PATH: 'The website base path contains unsupported URL characters.',\n INVALID_SEARCH_INDEX: 'The documentation search index is invalid.',\n} as const satisfies Readonly<Record<IWebsiteUiConfigurationErrorCode, string>>;\n\n/** Represents invalid configuration or generated input at a website UI boundary. */\nexport class WebsiteUiConfigurationException extends Exception {\n public override readonly code: IWebsiteUiConfigurationErrorCode;\n\n /** Creates the stable configuration exception for one failed boundary. */\n public constructor(code: IWebsiteUiConfigurationErrorCode) {\n super(CONFIGURATION_ERROR_MESSAGES[code], code);\n this.code = code;\n this.name = 'WebsiteUiConfigurationException';\n }\n}\n"],"mappings":";;AAKA,IAAM,+BAA+B;CACnC,mBAAmB;CACnB,sBAAsB;AACxB;;AAGA,IAAa,kCAAb,cAAqD,UAAU;CAC7D;;CAGA,YAAmB,MAAwC;EACzD,MAAM,6BAA6B,OAAO,IAAI;EAC9C,KAAK,OAAO;EACZ,KAAK,OAAO;CACd;AACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Exception } from 'error-message-utils';
|
|
2
|
+
export type IWebsiteUiConfigurationErrorCode = 'INVALID_BASE_PATH' | 'INVALID_SEARCH_INDEX';
|
|
3
|
+
/** Represents invalid configuration or generated input at a website UI boundary. */
|
|
4
|
+
export declare class WebsiteUiConfigurationException extends Exception {
|
|
5
|
+
readonly code: IWebsiteUiConfigurationErrorCode;
|
|
6
|
+
/** Creates the stable configuration exception for one failed boundary. */
|
|
7
|
+
constructor(code: IWebsiteUiConfigurationErrorCode);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=exceptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../src/exceptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,MAAM,MAAM,gCAAgC,GAAG,mBAAmB,GAAG,sBAAsB,CAAC;AAO5F,oFAAoF;AACpF,qBAAa,+BAAgC,SAAQ,SAAS;IAC5D,SAAyB,IAAI,EAAE,gCAAgC,CAAC;IAEhE,0EAA0E;gBACvD,IAAI,EAAE,gCAAgC;CAK1D"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { WebsiteUiConfigurationException } from './exceptions.js';
|
|
2
|
+
export type { IWebsiteUiConfigurationErrorCode } from './exceptions.js';
|
|
3
|
+
export { parseSearchDocuments, searchDocuments } from './search/index.js';
|
|
4
|
+
export type { ISearchDocument } from './search/index.js';
|
|
5
|
+
export { DEFAULT_BASE_PATH, createCanonicalUrl, isPublicRouteActive, normalizeBasePath, withBase, } from './site/index.js';
|
|
6
|
+
export { isDarkTheme, parseThemePreference } from './theme/index.js';
|
|
7
|
+
export type { IThemePreference } from './theme/index.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAClE,YAAY,EAAE,gCAAgC,EAAE,MAAM,iBAAiB,CAAC;AAGxE,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC1E,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,QAAQ,GACT,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { t as WebsiteUiConfigurationException } from "./chunks/exceptions-BYCwx4kO.js";
|
|
2
|
+
import { parseSearchDocuments, searchDocuments } from "./search.js";
|
|
3
|
+
import { DEFAULT_BASE_PATH, createCanonicalUrl, isPublicRouteActive, normalizeBasePath, withBase } from "./site.js";
|
|
4
|
+
import { isDarkTheme, parseThemePreference } from "./theme.js";
|
|
5
|
+
export { DEFAULT_BASE_PATH, WebsiteUiConfigurationException, createCanonicalUrl, isDarkTheme, isPublicRouteActive, normalizeBasePath, parseSearchDocuments, parseThemePreference, searchDocuments, withBase };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ISearchDocument {
|
|
2
|
+
description: string;
|
|
3
|
+
searchText: string;
|
|
4
|
+
title: string;
|
|
5
|
+
url: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Validates the generated browser search-index boundary.
|
|
9
|
+
* @param source Unknown parsed search-index value.
|
|
10
|
+
* @returns Validated public search documents.
|
|
11
|
+
* @throws
|
|
12
|
+
* - INVALID_SEARCH_INDEX: The documentation search index is invalid.
|
|
13
|
+
*/
|
|
14
|
+
export declare const parseSearchDocuments: (source: unknown) => ISearchDocument[];
|
|
15
|
+
/**
|
|
16
|
+
* Searches public documentation locally with deterministic relevance and ordering.
|
|
17
|
+
* @param query Developer-entered search query.
|
|
18
|
+
* @param documents Generated public search documents.
|
|
19
|
+
* @returns The highest-scoring matching documents.
|
|
20
|
+
*/
|
|
21
|
+
export declare const searchDocuments: (query: string, documents: ISearchDocument[]) => ISearchDocument[];
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AA+CD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,OAAO,KAAG,eAAe,EAMrE,CAAC;AAuBF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,EAAE,WAAW,eAAe,EAAE,KAAG,eAAe,EAoB5F,CAAC"}
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { t as WebsiteUiConfigurationException } from "./chunks/exceptions-BYCwx4kO.js";
|
|
2
|
+
//#region src/search/index.ts
|
|
3
|
+
var SEARCH_RESULT_LIMIT = 16;
|
|
4
|
+
var SEARCH_URL_ORIGIN = "https://website-ui.invalid";
|
|
5
|
+
var normalizeSearchValue = (source) => source.normalize("NFKD").replaceAll(/\p{M}/gu, "").toLocaleLowerCase("en").replaceAll(/\s+/g, " ").trim();
|
|
6
|
+
var isSafeSearchUrl = (source) => {
|
|
7
|
+
const hasUnsupportedCharacter = [...source].some((character) => {
|
|
8
|
+
const codePoint = character.codePointAt(0);
|
|
9
|
+
return character === "\\" || codePoint === void 0 || codePoint <= 31 || codePoint === 127;
|
|
10
|
+
});
|
|
11
|
+
if (!source.startsWith("/") || source.startsWith("//") || hasUnsupportedCharacter) return false;
|
|
12
|
+
try {
|
|
13
|
+
return new URL(source, SEARCH_URL_ORIGIN).origin === SEARCH_URL_ORIGIN;
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var isSearchDocument = (source) => {
|
|
19
|
+
if (!source || typeof source !== "object") return false;
|
|
20
|
+
const candidate = source;
|
|
21
|
+
return typeof candidate["description"] === "string" && typeof candidate["searchText"] === "string" && typeof candidate["title"] === "string" && typeof candidate["url"] === "string" && isSafeSearchUrl(candidate["url"]);
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Validates the generated browser search-index boundary.
|
|
25
|
+
* @param source Unknown parsed search-index value.
|
|
26
|
+
* @returns Validated public search documents.
|
|
27
|
+
* @throws
|
|
28
|
+
* - INVALID_SEARCH_INDEX: The documentation search index is invalid.
|
|
29
|
+
*/
|
|
30
|
+
var parseSearchDocuments = (source) => {
|
|
31
|
+
if (!Array.isArray(source) || !source.every(isSearchDocument)) throw new WebsiteUiConfigurationException("INVALID_SEARCH_INDEX");
|
|
32
|
+
return source;
|
|
33
|
+
};
|
|
34
|
+
var getSearchScore = (query, tokens, document) => {
|
|
35
|
+
const title = normalizeSearchValue(document.title);
|
|
36
|
+
const description = normalizeSearchValue(document.description);
|
|
37
|
+
const searchText = normalizeSearchValue(document.searchText);
|
|
38
|
+
const completeText = `${title} ${description} ${searchText}`;
|
|
39
|
+
if (!tokens.every((token) => completeText.includes(token))) return -1;
|
|
40
|
+
let score = title === query ? 64 : title.startsWith(query) ? 32 : 0;
|
|
41
|
+
for (const token of tokens) {
|
|
42
|
+
if (title.includes(token)) score += 16;
|
|
43
|
+
if (description.includes(token)) score += 4;
|
|
44
|
+
if (searchText.includes(token)) score += 1;
|
|
45
|
+
}
|
|
46
|
+
return score;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Searches public documentation locally with deterministic relevance and ordering.
|
|
50
|
+
* @param query Developer-entered search query.
|
|
51
|
+
* @param documents Generated public search documents.
|
|
52
|
+
* @returns The highest-scoring matching documents.
|
|
53
|
+
*/
|
|
54
|
+
var searchDocuments = (query, documents) => {
|
|
55
|
+
const normalizedQuery = normalizeSearchValue(query);
|
|
56
|
+
if (!normalizedQuery) return [];
|
|
57
|
+
const tokens = [...new Set(normalizedQuery.split(" "))];
|
|
58
|
+
return documents.map((document) => ({
|
|
59
|
+
document,
|
|
60
|
+
score: getSearchScore(normalizedQuery, tokens, document)
|
|
61
|
+
})).filter(({ score }) => score >= 0).sort((left, right) => right.score - left.score || left.document.title.localeCompare(right.document.title) || left.document.url.localeCompare(right.document.url)).slice(0, SEARCH_RESULT_LIMIT).map(({ document }) => document);
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { parseSearchDocuments, searchDocuments };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","names":[],"sources":["../src/search/index.ts"],"sourcesContent":["import { WebsiteUiConfigurationException } from '../exceptions.js';\n\n// one base-aware public document delivered by a static search index\nexport interface ISearchDocument {\n description: string;\n searchText: string;\n title: string;\n url: string;\n}\n\nconst SEARCH_RESULT_LIMIT = 16;\nconst SEARCH_URL_ORIGIN = 'https://website-ui.invalid';\n\nconst normalizeSearchValue = (source: string): string =>\n source\n .normalize('NFKD')\n .replaceAll(/\\p{M}/gu, '')\n .toLocaleLowerCase('en')\n .replaceAll(/\\s+/g, ' ')\n .trim();\n\nconst isSafeSearchUrl = (source: string): boolean => {\n const hasUnsupportedCharacter = [...source].some((character) => {\n const codePoint = character.codePointAt(0);\n\n return character === '\\\\' || codePoint === undefined || codePoint <= 31 || codePoint === 127;\n });\n\n if (!source.startsWith('/') || source.startsWith('//') || hasUnsupportedCharacter) {\n return false;\n }\n\n try {\n return new URL(source, SEARCH_URL_ORIGIN).origin === SEARCH_URL_ORIGIN;\n } catch {\n return false;\n }\n};\n\nconst isSearchDocument = (source: unknown): source is ISearchDocument => {\n if (!source || typeof source !== 'object') {\n return false;\n }\n\n const candidate = source as Record<string, unknown>;\n\n return (\n typeof candidate['description'] === 'string' &&\n typeof candidate['searchText'] === 'string' &&\n typeof candidate['title'] === 'string' &&\n typeof candidate['url'] === 'string' &&\n isSafeSearchUrl(candidate['url'])\n );\n};\n\n/**\n * Validates the generated browser search-index boundary.\n * @param source Unknown parsed search-index value.\n * @returns Validated public search documents.\n * @throws\n * - INVALID_SEARCH_INDEX: The documentation search index is invalid.\n */\nexport const parseSearchDocuments = (source: unknown): ISearchDocument[] => {\n if (!Array.isArray(source) || !source.every(isSearchDocument)) {\n throw new WebsiteUiConfigurationException('INVALID_SEARCH_INDEX');\n }\n\n return source;\n};\n\nconst getSearchScore = (query: string, tokens: string[], document: ISearchDocument): number => {\n const title = normalizeSearchValue(document.title);\n const description = normalizeSearchValue(document.description);\n const searchText = normalizeSearchValue(document.searchText);\n const completeText = `${title} ${description} ${searchText}`;\n\n if (!tokens.every((token) => completeText.includes(token))) {\n return -1;\n }\n\n let score = title === query ? 64 : title.startsWith(query) ? 32 : 0;\n\n for (const token of tokens) {\n if (title.includes(token)) score += 16;\n if (description.includes(token)) score += 4;\n if (searchText.includes(token)) score += 1;\n }\n\n return score;\n};\n\n/**\n * Searches public documentation locally with deterministic relevance and ordering.\n * @param query Developer-entered search query.\n * @param documents Generated public search documents.\n * @returns The highest-scoring matching documents.\n */\nexport const searchDocuments = (query: string, documents: ISearchDocument[]): ISearchDocument[] => {\n const normalizedQuery = normalizeSearchValue(query);\n\n if (!normalizedQuery) {\n return [];\n }\n\n const tokens = [...new Set(normalizedQuery.split(' '))];\n\n return documents\n .map((document) => ({ document, score: getSearchScore(normalizedQuery, tokens, document) }))\n .filter(({ score }) => score >= 0)\n .sort(\n (left, right) =>\n right.score - left.score ||\n left.document.title.localeCompare(right.document.title) ||\n left.document.url.localeCompare(right.document.url),\n )\n .slice(0, SEARCH_RESULT_LIMIT)\n .map(({ document }) => document);\n};\n"],"mappings":";;AAUA,IAAM,sBAAsB;AAC5B,IAAM,oBAAoB;AAE1B,IAAM,wBAAwB,WAC5B,OACG,UAAU,MAAM,CAAC,CACjB,WAAW,WAAW,EAAE,CAAC,CACzB,kBAAkB,IAAI,CAAC,CACvB,WAAW,QAAQ,GAAG,CAAC,CACvB,KAAK;AAEV,IAAM,mBAAmB,WAA4B;CACnD,MAAM,0BAA0B,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,cAAc;EAC9D,MAAM,YAAY,UAAU,YAAY,CAAC;EAEzC,OAAO,cAAc,QAAQ,cAAc,KAAA,KAAa,aAAa,MAAM,cAAc;CAC3F,CAAC;CAED,IAAI,CAAC,OAAO,WAAW,GAAG,KAAK,OAAO,WAAW,IAAI,KAAK,yBACxD,OAAO;CAGT,IAAI;EACF,OAAO,IAAI,IAAI,QAAQ,iBAAiB,CAAC,CAAC,WAAW;CACvD,QAAQ;EACN,OAAO;CACT;AACF;AAEA,IAAM,oBAAoB,WAA+C;CACvE,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,OAAO;CAGT,MAAM,YAAY;CAElB,OACE,OAAO,UAAU,mBAAmB,YACpC,OAAO,UAAU,kBAAkB,YACnC,OAAO,UAAU,aAAa,YAC9B,OAAO,UAAU,WAAW,YAC5B,gBAAgB,UAAU,MAAM;AAEpC;;;;;;;;AASA,IAAa,wBAAwB,WAAuC;CAC1E,IAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,CAAC,OAAO,MAAM,gBAAgB,GAC1D,MAAM,IAAI,gCAAgC,sBAAsB;CAGlE,OAAO;AACT;AAEA,IAAM,kBAAkB,OAAe,QAAkB,aAAsC;CAC7F,MAAM,QAAQ,qBAAqB,SAAS,KAAK;CACjD,MAAM,cAAc,qBAAqB,SAAS,WAAW;CAC7D,MAAM,aAAa,qBAAqB,SAAS,UAAU;CAC3D,MAAM,eAAe,GAAG,MAAM,GAAG,YAAY,GAAG;CAEhD,IAAI,CAAC,OAAO,OAAO,UAAU,aAAa,SAAS,KAAK,CAAC,GACvD,OAAO;CAGT,IAAI,QAAQ,UAAU,QAAQ,KAAK,MAAM,WAAW,KAAK,IAAI,KAAK;CAElE,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,MAAM,SAAS,KAAK,GAAG,SAAS;EACpC,IAAI,YAAY,SAAS,KAAK,GAAG,SAAS;EAC1C,IAAI,WAAW,SAAS,KAAK,GAAG,SAAS;CAC3C;CAEA,OAAO;AACT;;;;;;;AAQA,IAAa,mBAAmB,OAAe,cAAoD;CACjG,MAAM,kBAAkB,qBAAqB,KAAK;CAElD,IAAI,CAAC,iBACH,OAAO,CAAC;CAGV,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,gBAAgB,MAAM,GAAG,CAAC,CAAC;CAEtD,OAAO,UACJ,KAAK,cAAc;EAAE;EAAU,OAAO,eAAe,iBAAiB,QAAQ,QAAQ;CAAE,EAAE,CAAC,CAC3F,QAAQ,EAAE,YAAY,SAAS,CAAC,CAAC,CACjC,MACE,MAAM,UACL,MAAM,QAAQ,KAAK,SACnB,KAAK,SAAS,MAAM,cAAc,MAAM,SAAS,KAAK,KACtD,KAAK,SAAS,IAAI,cAAc,MAAM,SAAS,GAAG,CACtD,CAAC,CACA,MAAM,GAAG,mBAAmB,CAAC,CAC7B,KAAK,EAAE,eAAe,QAAQ;AACnC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const DEFAULT_BASE_PATH = "/";
|
|
2
|
+
/**
|
|
3
|
+
* Returns one normalized root-relative base path with a trailing slash.
|
|
4
|
+
* @param basePath Candidate public base path.
|
|
5
|
+
* @returns The normalized public base path.
|
|
6
|
+
* @throws
|
|
7
|
+
* - INVALID_BASE_PATH: The website base path contains unsupported URL characters.
|
|
8
|
+
*/
|
|
9
|
+
export declare const normalizeBasePath: (basePath: string) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Prefixes one root-relative public route with the configured deployment base.
|
|
12
|
+
* @param route Root-relative public route.
|
|
13
|
+
* @param basePath Configured public base path.
|
|
14
|
+
* @returns The base-aware route.
|
|
15
|
+
* @throws
|
|
16
|
+
* - INVALID_BASE_PATH: The website base path contains unsupported URL characters.
|
|
17
|
+
*/
|
|
18
|
+
export declare const withBase: (route: string, basePath?: string) => string;
|
|
19
|
+
/**
|
|
20
|
+
* Checks whether a public pathname identifies a route or one of its descendants.
|
|
21
|
+
* @param pathname Current public pathname.
|
|
22
|
+
* @param route Root-relative public route.
|
|
23
|
+
* @param basePath Configured public base path.
|
|
24
|
+
* @returns Whether the route is active for the current pathname.
|
|
25
|
+
* @throws
|
|
26
|
+
* - INVALID_BASE_PATH: The website base path contains unsupported URL characters.
|
|
27
|
+
*/
|
|
28
|
+
export declare const isPublicRouteActive: (pathname: string, route: string, basePath?: string) => boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Builds a canonical absolute URL from an origin, base path, and public route.
|
|
31
|
+
* @param route Root-relative public route.
|
|
32
|
+
* @param siteUrl Public website origin.
|
|
33
|
+
* @param basePath Public deployment base path.
|
|
34
|
+
* @returns The canonical absolute URL.
|
|
35
|
+
* @throws
|
|
36
|
+
* - INVALID_BASE_PATH: The website base path contains unsupported URL characters.
|
|
37
|
+
*/
|
|
38
|
+
export declare const createCanonicalUrl: (route: string, siteUrl: string, basePath: string) => string;
|
|
39
|
+
export { WebsiteUiConfigurationException } from '../exceptions.js';
|
|
40
|
+
export type { IWebsiteUiConfigurationErrorCode } from '../exceptions.js';
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/site/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,KAAG,MASpD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,EAAE,iBAA4B,KAAG,MAKtE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,EAChB,OAAO,MAAM,EACb,iBAA4B,KAC3B,OAMF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,EAAE,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,MACpC,CAAC;AAGnD,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EAAE,gCAAgC,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/site.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { t as WebsiteUiConfigurationException } from "./chunks/exceptions-BYCwx4kO.js";
|
|
2
|
+
//#region src/site/index.ts
|
|
3
|
+
var DEFAULT_BASE_PATH = "/";
|
|
4
|
+
/**
|
|
5
|
+
* Returns one normalized root-relative base path with a trailing slash.
|
|
6
|
+
* @param basePath Candidate public base path.
|
|
7
|
+
* @returns The normalized public base path.
|
|
8
|
+
* @throws
|
|
9
|
+
* - INVALID_BASE_PATH: The website base path contains unsupported URL characters.
|
|
10
|
+
*/
|
|
11
|
+
var normalizeBasePath = (basePath) => {
|
|
12
|
+
const path = `/${basePath}`.replaceAll(/\/{2,}/g, "/");
|
|
13
|
+
const normalizedPath = path === "/" ? "/" : `${path.replace(/\/$/, "")}/`;
|
|
14
|
+
if (!/^\/(?:[a-zA-Z0-9._~-]+\/)*$/u.test(normalizedPath)) throw new WebsiteUiConfigurationException("INVALID_BASE_PATH");
|
|
15
|
+
return normalizedPath;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Prefixes one root-relative public route with the configured deployment base.
|
|
19
|
+
* @param route Root-relative public route.
|
|
20
|
+
* @param basePath Configured public base path.
|
|
21
|
+
* @returns The base-aware route.
|
|
22
|
+
* @throws
|
|
23
|
+
* - INVALID_BASE_PATH: The website base path contains unsupported URL characters.
|
|
24
|
+
*/
|
|
25
|
+
var withBase = (route, basePath = "/") => {
|
|
26
|
+
return `${normalizeBasePath(basePath)}${route.replace(/^\//, "")}`.replaceAll(/\/{2,}/g, "/");
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Checks whether a public pathname identifies a route or one of its descendants.
|
|
30
|
+
* @param pathname Current public pathname.
|
|
31
|
+
* @param route Root-relative public route.
|
|
32
|
+
* @param basePath Configured public base path.
|
|
33
|
+
* @returns Whether the route is active for the current pathname.
|
|
34
|
+
* @throws
|
|
35
|
+
* - INVALID_BASE_PATH: The website base path contains unsupported URL characters.
|
|
36
|
+
*/
|
|
37
|
+
var isPublicRouteActive = (pathname, route, basePath = "/") => {
|
|
38
|
+
const publicRoute = withBase(route, basePath);
|
|
39
|
+
return publicRoute === normalizeBasePath(basePath) ? pathname === publicRoute : pathname.startsWith(publicRoute);
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Builds a canonical absolute URL from an origin, base path, and public route.
|
|
43
|
+
* @param route Root-relative public route.
|
|
44
|
+
* @param siteUrl Public website origin.
|
|
45
|
+
* @param basePath Public deployment base path.
|
|
46
|
+
* @returns The canonical absolute URL.
|
|
47
|
+
* @throws
|
|
48
|
+
* - INVALID_BASE_PATH: The website base path contains unsupported URL characters.
|
|
49
|
+
*/
|
|
50
|
+
var createCanonicalUrl = (route, siteUrl, basePath) => new URL(withBase(route, basePath), siteUrl).href;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { DEFAULT_BASE_PATH, WebsiteUiConfigurationException, createCanonicalUrl, isPublicRouteActive, normalizeBasePath, withBase };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=site.js.map
|
package/dist/site.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site.js","names":[],"sources":["../src/site/index.ts"],"sourcesContent":["import { WebsiteUiConfigurationException } from '../exceptions.js';\n\n// default public base path used outside framework-owned configuration\nexport const DEFAULT_BASE_PATH = '/';\n\n/**\n * Returns one normalized root-relative base path with a trailing slash.\n * @param basePath Candidate public base path.\n * @returns The normalized public base path.\n * @throws\n * - INVALID_BASE_PATH: The website base path contains unsupported URL characters.\n */\nexport const normalizeBasePath = (basePath: string): string => {\n const path = `/${basePath}`.replaceAll(/\\/{2,}/g, '/');\n const normalizedPath = path === '/' ? '/' : `${path.replace(/\\/$/, '')}/`;\n\n if (!/^\\/(?:[a-zA-Z0-9._~-]+\\/)*$/u.test(normalizedPath)) {\n throw new WebsiteUiConfigurationException('INVALID_BASE_PATH');\n }\n\n return normalizedPath;\n};\n\n/**\n * Prefixes one root-relative public route with the configured deployment base.\n * @param route Root-relative public route.\n * @param basePath Configured public base path.\n * @returns The base-aware route.\n * @throws\n * - INVALID_BASE_PATH: The website base path contains unsupported URL characters.\n */\nexport const withBase = (route: string, basePath = DEFAULT_BASE_PATH): string => {\n const base = normalizeBasePath(basePath);\n const routeWithoutRoot = route.replace(/^\\//, '');\n\n return `${base}${routeWithoutRoot}`.replaceAll(/\\/{2,}/g, '/');\n};\n\n/**\n * Checks whether a public pathname identifies a route or one of its descendants.\n * @param pathname Current public pathname.\n * @param route Root-relative public route.\n * @param basePath Configured public base path.\n * @returns Whether the route is active for the current pathname.\n * @throws\n * - INVALID_BASE_PATH: The website base path contains unsupported URL characters.\n */\nexport const isPublicRouteActive = (\n pathname: string,\n route: string,\n basePath = DEFAULT_BASE_PATH,\n): boolean => {\n const publicRoute = withBase(route, basePath);\n\n return publicRoute === normalizeBasePath(basePath)\n ? pathname === publicRoute\n : pathname.startsWith(publicRoute);\n};\n\n/**\n * Builds a canonical absolute URL from an origin, base path, and public route.\n * @param route Root-relative public route.\n * @param siteUrl Public website origin.\n * @param basePath Public deployment base path.\n * @returns The canonical absolute URL.\n * @throws\n * - INVALID_BASE_PATH: The website base path contains unsupported URL characters.\n */\nexport const createCanonicalUrl = (route: string, siteUrl: string, basePath: string): string =>\n new URL(withBase(route, basePath), siteUrl).href;\n\n// exceptions\nexport { WebsiteUiConfigurationException } from '../exceptions.js';\nexport type { IWebsiteUiConfigurationErrorCode } from '../exceptions.js';\n"],"mappings":";;AAGA,IAAa,oBAAoB;;;;;;;;AASjC,IAAa,qBAAqB,aAA6B;CAC7D,MAAM,OAAO,IAAI,WAAW,WAAW,WAAW,GAAG;CACrD,MAAM,iBAAiB,SAAS,MAAM,MAAM,GAAG,KAAK,QAAQ,OAAO,EAAE,EAAE;CAEvE,IAAI,CAAC,+BAA+B,KAAK,cAAc,GACrD,MAAM,IAAI,gCAAgC,mBAAmB;CAG/D,OAAO;AACT;;;;;;;;;AAUA,IAAa,YAAY,OAAe,WAAA,QAAyC;CAI/E,OAAO,GAHM,kBAAkB,QAGrB,IAFe,MAAM,QAAQ,OAAO,EAE7B,IAAmB,WAAW,WAAW,GAAG;AAC/D;;;;;;;;;;AAWA,IAAa,uBACX,UACA,OACA,WAAA,QACY;CACZ,MAAM,cAAc,SAAS,OAAO,QAAQ;CAE5C,OAAO,gBAAgB,kBAAkB,QAAQ,IAC7C,aAAa,cACb,SAAS,WAAW,WAAW;AACrC;;;;;;;;;;AAWA,IAAa,sBAAsB,OAAe,SAAiB,aACjE,IAAI,IAAI,SAAS,OAAO,QAAQ,GAAG,OAAO,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type IThemePreference = 'dark' | 'light' | 'system';
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes an unknown persisted preference to a supported theme choice.
|
|
4
|
+
* @param value Persisted storage value.
|
|
5
|
+
* @returns A supported explicit or system preference.
|
|
6
|
+
*/
|
|
7
|
+
export declare const parseThemePreference: (value: unknown) => IThemePreference;
|
|
8
|
+
/**
|
|
9
|
+
* Resolves whether the effective theme should be dark.
|
|
10
|
+
* @param preference Explicit or system theme preference.
|
|
11
|
+
* @param doesSystemPreferDark Current operating-system preference.
|
|
12
|
+
* @returns Whether the effective website theme is dark.
|
|
13
|
+
*/
|
|
14
|
+
export declare const isDarkTheme: (preference: IThemePreference, doesSystemPreferDark: boolean) => boolean;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,OAAO,KAAG,gBAC0B,CAAC;AAEjF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,YAAY,gBAAgB,EAAE,sBAAsB,OAAO,KAAG,OACd,CAAC"}
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/theme/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes an unknown persisted preference to a supported theme choice.
|
|
4
|
+
* @param value Persisted storage value.
|
|
5
|
+
* @returns A supported explicit or system preference.
|
|
6
|
+
*/
|
|
7
|
+
var parseThemePreference = (value) => value === "dark" || value === "light" || value === "system" ? value : "system";
|
|
8
|
+
/**
|
|
9
|
+
* Resolves whether the effective theme should be dark.
|
|
10
|
+
* @param preference Explicit or system theme preference.
|
|
11
|
+
* @param doesSystemPreferDark Current operating-system preference.
|
|
12
|
+
* @returns Whether the effective website theme is dark.
|
|
13
|
+
*/
|
|
14
|
+
var isDarkTheme = (preference, doesSystemPreferDark) => preference === "dark" || preference === "system" && doesSystemPreferDark;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { isDarkTheme, parseThemePreference };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","names":[],"sources":["../src/theme/index.ts"],"sourcesContent":["// persisted website theme choices\nexport type IThemePreference = 'dark' | 'light' | 'system';\n\n/**\n * Normalizes an unknown persisted preference to a supported theme choice.\n * @param value Persisted storage value.\n * @returns A supported explicit or system preference.\n */\nexport const parseThemePreference = (value: unknown): IThemePreference =>\n value === 'dark' || value === 'light' || value === 'system' ? value : 'system';\n\n/**\n * Resolves whether the effective theme should be dark.\n * @param preference Explicit or system theme preference.\n * @param doesSystemPreferDark Current operating-system preference.\n * @returns Whether the effective website theme is dark.\n */\nexport const isDarkTheme = (preference: IThemePreference, doesSystemPreferDark: boolean): boolean =>\n preference === 'dark' || (preference === 'system' && doesSystemPreferDark);\n"],"mappings":";;;;;;AAQA,IAAa,wBAAwB,UACnC,UAAU,UAAU,UAAU,WAAW,UAAU,WAAW,QAAQ;;;;;;;AAQxE,IAAa,eAAe,YAA8B,yBACxD,eAAe,UAAW,eAAe,YAAY"}
|
package/package.json
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@moldea.ai/website-ui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared Astro foundations for moldea public websites.",
|
|
5
|
+
"homepage": "https://github.com/moldea-ai/packages/tree/main/projects/website-ui#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/moldea-ai/packages/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/moldea-ai/packages.git",
|
|
12
|
+
"directory": "projects/website-ui"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Jesus Graterol",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": [
|
|
18
|
+
"./src/**/*.astro",
|
|
19
|
+
"./src/**/*.css"
|
|
20
|
+
],
|
|
21
|
+
"files": [
|
|
22
|
+
"cover.png",
|
|
23
|
+
"dist",
|
|
24
|
+
"src/**/*.astro",
|
|
25
|
+
"src/**/*.css",
|
|
26
|
+
"src/exceptions.ts",
|
|
27
|
+
"src/search/index.ts",
|
|
28
|
+
"src/site/index.ts",
|
|
29
|
+
"src/theme/index.ts",
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"import": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./site": {
|
|
39
|
+
"types": "./dist/site/index.d.ts",
|
|
40
|
+
"import": "./dist/site.js"
|
|
41
|
+
},
|
|
42
|
+
"./search": {
|
|
43
|
+
"types": "./dist/search/index.d.ts",
|
|
44
|
+
"import": "./dist/search.js"
|
|
45
|
+
},
|
|
46
|
+
"./theme": {
|
|
47
|
+
"types": "./dist/theme/index.d.ts",
|
|
48
|
+
"import": "./dist/theme.js"
|
|
49
|
+
},
|
|
50
|
+
"./action-button": {
|
|
51
|
+
"import": "./src/components/action-button/action-button.component.astro"
|
|
52
|
+
},
|
|
53
|
+
"./action-link": {
|
|
54
|
+
"import": "./src/components/action-link/action-link.component.astro"
|
|
55
|
+
},
|
|
56
|
+
"./brand-logo": {
|
|
57
|
+
"import": "./src/components/brand-logo/brand-logo.component.astro"
|
|
58
|
+
},
|
|
59
|
+
"./breadcrumbs": {
|
|
60
|
+
"import": "./src/components/breadcrumbs/breadcrumbs.component.astro"
|
|
61
|
+
},
|
|
62
|
+
"./inline-brand-text": {
|
|
63
|
+
"import": "./src/components/inline-brand-text/inline-brand-text.component.astro"
|
|
64
|
+
},
|
|
65
|
+
"./local-search": {
|
|
66
|
+
"import": "./src/components/local-search/local-search.component.astro"
|
|
67
|
+
},
|
|
68
|
+
"./theme-bootstrap": {
|
|
69
|
+
"import": "./src/components/theme-bootstrap/theme-bootstrap.component.astro"
|
|
70
|
+
},
|
|
71
|
+
"./theme-control": {
|
|
72
|
+
"import": "./src/components/theme-control/theme-control.component.astro"
|
|
73
|
+
},
|
|
74
|
+
"./styles.css": {
|
|
75
|
+
"style": "./src/styles.css",
|
|
76
|
+
"default": "./src/styles.css"
|
|
77
|
+
},
|
|
78
|
+
"./tokens.css": {
|
|
79
|
+
"style": "./src/tokens.css",
|
|
80
|
+
"default": "./src/tokens.css"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"main": "./dist/index.js",
|
|
84
|
+
"types": "./dist/index.d.ts",
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"@fontsource-variable/ubuntu-sans": "5.2.10",
|
|
87
|
+
"@lucide/astro": "1.31.0",
|
|
88
|
+
"error-message-utils": "1.2.11"
|
|
89
|
+
},
|
|
90
|
+
"peerDependencies": {
|
|
91
|
+
"astro": "7.2.2",
|
|
92
|
+
"tailwindcss": "4.3.3"
|
|
93
|
+
},
|
|
94
|
+
"devDependencies": {
|
|
95
|
+
"@types/node": "22.20.1",
|
|
96
|
+
"astro": "7.2.2",
|
|
97
|
+
"tailwindcss": "4.3.3",
|
|
98
|
+
"typescript": "6.0.3",
|
|
99
|
+
"vite": "8.2.1",
|
|
100
|
+
"vitest": "4.1.10",
|
|
101
|
+
"web-utils-kit": "1.3.1"
|
|
102
|
+
},
|
|
103
|
+
"engines": {
|
|
104
|
+
"node": "^24.15.0"
|
|
105
|
+
},
|
|
106
|
+
"publishConfig": {
|
|
107
|
+
"access": "public"
|
|
108
|
+
},
|
|
109
|
+
"scripts": {
|
|
110
|
+
"build": "vite build --emptyOutDir && tsc -p tsconfig.build.json",
|
|
111
|
+
"dev": "vite build --watch",
|
|
112
|
+
"lint": "eslint src vite.config.ts vitest",
|
|
113
|
+
"test": "pnpm run test:unit && pnpm run test:integration",
|
|
114
|
+
"test:integration": "pnpm run build && vitest run --config vitest/test-integration.config.ts",
|
|
115
|
+
"test:unit": "vitest run --config vitest/test-unit.config.ts",
|
|
116
|
+
"typecheck": "tsc -p tsconfig.src.json --noEmit && tsc -p tsconfig.json --noEmit"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types';
|
|
3
|
+
|
|
4
|
+
export interface Props extends Omit<HTMLAttributes<'button'>, 'class'> {
|
|
5
|
+
class?: string;
|
|
6
|
+
size?: 'icon' | 'lg' | 'md' | 'sm';
|
|
7
|
+
variant?: 'ghost' | 'link' | 'outline' | 'primary' | 'secondary';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
class: className,
|
|
12
|
+
size = 'md',
|
|
13
|
+
type = 'button',
|
|
14
|
+
variant = 'primary',
|
|
15
|
+
...attributes
|
|
16
|
+
} = Astro.props;
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<button
|
|
20
|
+
class:list={['action-control', `action-${variant}`, `action-size-${size}`, className]}
|
|
21
|
+
{type}
|
|
22
|
+
{...attributes}
|
|
23
|
+
>
|
|
24
|
+
<slot />
|
|
25
|
+
</button>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types';
|
|
3
|
+
|
|
4
|
+
export interface Props extends Omit<HTMLAttributes<'a'>, 'class'> {
|
|
5
|
+
class?: string;
|
|
6
|
+
size?: 'icon' | 'lg' | 'md' | 'sm';
|
|
7
|
+
variant?: 'ghost' | 'link' | 'outline' | 'primary' | 'secondary';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { class: className, size = 'md', variant = 'primary', ...attributes } = Astro.props;
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<a
|
|
14
|
+
class:list={['action-control', `action-${variant}`, `action-size-${size}`, className]}
|
|
15
|
+
{...attributes}
|
|
16
|
+
>
|
|
17
|
+
<slot />
|
|
18
|
+
</a>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { withBase } from '../../site/index.ts';
|
|
3
|
+
|
|
4
|
+
export interface Props {
|
|
5
|
+
basePath?: string;
|
|
6
|
+
compact?: boolean;
|
|
7
|
+
darkCompactLogoPath: string;
|
|
8
|
+
darkLogoPath: string;
|
|
9
|
+
homeLabel: string;
|
|
10
|
+
lightCompactLogoPath: string;
|
|
11
|
+
lightLogoPath: string;
|
|
12
|
+
suffix?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
basePath = import.meta.env.BASE_URL,
|
|
17
|
+
compact = false,
|
|
18
|
+
darkCompactLogoPath,
|
|
19
|
+
darkLogoPath,
|
|
20
|
+
homeLabel,
|
|
21
|
+
lightCompactLogoPath,
|
|
22
|
+
lightLogoPath,
|
|
23
|
+
suffix,
|
|
24
|
+
} = Astro.props;
|
|
25
|
+
const darkAssetPath = compact ? darkCompactLogoPath : darkLogoPath;
|
|
26
|
+
const lightAssetPath = compact ? lightCompactLogoPath : lightLogoPath;
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
<a
|
|
30
|
+
class="inline-flex min-w-0 items-center gap-3 rounded-md"
|
|
31
|
+
href={withBase('/', basePath)}
|
|
32
|
+
aria-label={homeLabel}
|
|
33
|
+
>
|
|
34
|
+
<img
|
|
35
|
+
class="hidden h-8 w-auto dark:block"
|
|
36
|
+
src={withBase(darkAssetPath, basePath)}
|
|
37
|
+
width={compact ? 185 : 942}
|
|
38
|
+
height="210"
|
|
39
|
+
alt=""
|
|
40
|
+
/>
|
|
41
|
+
<img
|
|
42
|
+
class="h-8 w-auto dark:hidden"
|
|
43
|
+
src={withBase(lightAssetPath, basePath)}
|
|
44
|
+
width={compact ? 185 : 942}
|
|
45
|
+
height="210"
|
|
46
|
+
alt=""
|
|
47
|
+
/>
|
|
48
|
+
{
|
|
49
|
+
suffix && (
|
|
50
|
+
<span class="inline border-s border-border ps-3 text-xs font-semibold text-muted-foreground">
|
|
51
|
+
{suffix}
|
|
52
|
+
</span>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
</a>
|