From 372992302f17ec59830cf9ad20e1ecdd2a978c52 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 5 May 2025 13:38:18 -0300 Subject: [PATCH 1/8] Fix pair redirect --- web/src/pages/[func].astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/pages/[func].astro b/web/src/pages/[func].astro index 6f3348a3..e44dcc31 100644 --- a/web/src/pages/[func].astro +++ b/web/src/pages/[func].astro @@ -46,7 +46,7 @@ if ( funcExamples.length > 0 ){ tableOfContents: false, }}> {funcPair && ( -

Pair: { funcPair }

+

Pair: { funcPair }

)} From 283cf4aba4ee1262641573fcfe48299406bd2bb5 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 5 May 2025 14:35:32 -0300 Subject: [PATCH 2/8] Add 'optional' property for parameters in function specification --- schemas/function.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schemas/function.yaml b/schemas/function.yaml index 3cb22238..de1a49f5 100644 --- a/schemas/function.yaml +++ b/schemas/function.yaml @@ -163,6 +163,10 @@ $defs: description: | The default value for this parameter, if none was given in the call to the function. This property automatically implicitly marks this parameter as optional. + optional: + type: boolean + default: false + description: If set to true, this parameter is optional. returns: type: object From 47cf67b7aa191bc0bd5c85051c97ab89743cf508 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 5 May 2025 14:58:09 -0300 Subject: [PATCH 3/8] Refactor function parameter and details structures for better type safety --- web/src/utils/functions.ts | 66 +++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/web/src/utils/functions.ts b/web/src/utils/functions.ts index b75c7151..85cfbc6d 100644 --- a/web/src/utils/functions.ts +++ b/web/src/utils/functions.ts @@ -5,26 +5,49 @@ import type { FunctionType } from './types'; type FunctionItem = Awaited>[number]; +// Define a structure for function parameters +type FunctionParameter = { + name: string; + type: string; // Adjust type as needed (e.g., string | string[]) + description?: string; + optional?: boolean; +}; + +// Define a structure for the details expected within shared/client/server +type FunctionDetails = { + description?: string; + pair?: boolean; + examples?: { code: string; description?: string }[]; + notes?: string; + parameters?: FunctionParameter[]; +}; + type FunctionsByCategory = { [folder: string]: FunctionItem[]; }; type FunctionsByTypeByCategory = { - shared: FunctionsByCategory; - client: FunctionsByCategory; - server: FunctionsByCategory; + [key in FunctionType]: FunctionsByCategory; }; + export type FunctionData = { shared?: any; client?: any; server?: any; }; +// Use the specific FunctionDetails type +export type TypedFunctionData = { + shared?: FunctionDetails; + client?: FunctionDetails; + server?: FunctionDetails; +}; + export const functionTypePrettyName = { 'client': 'Client-side', 'server': 'Server-side', 'shared': 'Shared', -}; +} as const; // Use 'as const' for stricter typing of keys function getFunctionType(data: FunctionData): FunctionType { if (data.shared) return 'shared'; @@ -32,17 +55,34 @@ function getFunctionType(data: FunctionData): FunctionType { return 'server'; } function getFunctionTypePretty(data: FunctionData): string { + // No need for fallback, getFunctionType guarantees a valid FunctionType const funcType = getFunctionType(data); - return functionTypePrettyName[funcType] ?? 'Server-side'; + return functionTypePrettyName[funcType]; } -export function getFunctionInfo(data: FunctionData): any { +// Define a return type for getFunctionInfo +export type FunctionInfo = { + description: string; + type: FunctionType; + typePretty: string; + pair: boolean; + examples: { code: string; description?: string }[]; + notes?: string; // Added notes + parameters?: FunctionParameter[]; // Added parameters +}; + +export function getFunctionInfo(data: TypedFunctionData): FunctionInfo { + const type = getFunctionType(data); + const details = data[type] ?? {}; // Get details based on type, default to empty object + return { - description: data.shared?.description || data.client?.description || data.server?.description || '', - type: getFunctionType(data), + description: details.description || '', + type: type, typePretty: getFunctionTypePretty(data), - pair: data.shared?.pair || data.client?.pair || data.server?.pair || false, - examples: data.shared?.examples || data.client?.examples || data.server?.examples || [ ], + pair: details.pair || false, + examples: details.examples || [], + notes: details.notes, // Extract notes (will be undefined if not present) + parameters: details.parameters || [], // Extract parameters }; } @@ -55,7 +95,8 @@ let functionsByTypeByCategory: FunctionsByTypeByCategory = { }; for (let func of functionsCollection) { - const normalizedPath = path.normalize(func.filePath || ''); + // Assuming func.filePath exists, handle potential undefined if necessary + const normalizedPath = path.normalize(func.id); // Use func.id which includes the path relative to content dir const folder = path.basename(path.dirname(normalizedPath)); if (!functionsByCategory[folder]) { functionsByCategory[folder] = []; @@ -63,7 +104,8 @@ for (let func of functionsCollection) { functionsByCategory[folder].push(func); const funcType = getFunctionType(func.data); - if (!functionsByTypeByCategory[funcType][folder]) { + // Ensure the folder exists for the specific type + if (!functionsByTypeByCategory[funcType]?.[folder]) { functionsByTypeByCategory[funcType][folder] = []; } functionsByTypeByCategory[funcType][folder].push(func); From 108ff858255150c0a70080b945171beba8f54f58 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 5 May 2025 15:10:55 -0300 Subject: [PATCH 4/8] Fix "notes" type --- web/src/utils/functions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/utils/functions.ts b/web/src/utils/functions.ts index 85cfbc6d..d5193cd1 100644 --- a/web/src/utils/functions.ts +++ b/web/src/utils/functions.ts @@ -18,7 +18,7 @@ type FunctionDetails = { description?: string; pair?: boolean; examples?: { code: string; description?: string }[]; - notes?: string; + notes?: string[]; parameters?: FunctionParameter[]; }; @@ -67,7 +67,7 @@ export type FunctionInfo = { typePretty: string; pair: boolean; examples: { code: string; description?: string }[]; - notes?: string; // Added notes + notes?: string[]; // Added notes parameters?: FunctionParameter[]; // Added parameters }; From 0667426188b08c2797b2be448512a582dc121cea Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 5 May 2025 16:04:14 -0300 Subject: [PATCH 5/8] Adds 'notes' display on function page. Add 'important notes' property to function schema and update notes display. Refactor style on pages --- schemas/function.yaml | 8 +++++ web/src/pages/[func].astro | 56 +++++++++++++++++++++++--------- web/src/styles/function-page.css | 39 ++++++++++++++++++++++ web/src/utils/functions.ts | 24 +++++++------- 4 files changed, 99 insertions(+), 28 deletions(-) create mode 100644 web/src/styles/function-page.css diff --git a/schemas/function.yaml b/schemas/function.yaml index de1a49f5..7e1e4bf2 100644 --- a/schemas/function.yaml +++ b/schemas/function.yaml @@ -43,6 +43,14 @@ $defs: description: type: string description: Describes the functionality provided by the function. + important_notes: + type: array + description: | + A list of important notes about the function. + This is a list of things that are important to know about the function, but not + necessarily related to the function itself. + items: + type: string notes: type: array description: List of noteworthy pieces of information for the function. diff --git a/web/src/pages/[func].astro b/web/src/pages/[func].astro index e44dcc31..84c6b86f 100644 --- a/web/src/pages/[func].astro +++ b/web/src/pages/[func].astro @@ -7,6 +7,8 @@ import fs from "fs"; import path from "path"; import { Code } from '@astrojs/starlight/components'; +import '@src/styles/function-page.css'; + export async function getStaticPaths() { const functions = await getCollection('functions'); return functions.map(func => ({ @@ -19,24 +21,30 @@ const { func } = Astro.props; const funcInfo = getFunctionInfo(func.data); const funcType = funcInfo.type; -const funcTypePretty = funcInfo.typePretty; - const funcPair = funcInfo.pair; -const funcPath = path.dirname(func.filePath ?? "") -let funcExamples = funcInfo.examples +const funcPath = path.dirname(func.filePath ?? ""); + +const { description, notes: funcNotes, examples: rawExamples } = funcInfo; -if ( funcExamples.length > 0 ){ - funcExamples = funcInfo.examples.map((example: any) => { +let processedExamples: any[] = []; +if (Array.isArray(rawExamples) && rawExamples.length > 0) { + processedExamples = rawExamples.map((example: any) => { try { - const luaCode = fs.readFileSync(path.resolve(`${funcPath}`, example.path), "utf8"); + const exampleFilePath = path.resolve(funcPath, example.path); + const luaCode = fs.readFileSync(exampleFilePath, "utf8"); return { ...example, luaCode }; } catch (error) { - console.error(`Error reading ${example.path}:`, error); - return { ...example, luaCode: "Loading example error." }; + console.error(`Error reading example file ${example.path} at ${path.resolve(funcPath, example.path)}:`, error); + return { ...example, luaCode: `Error loading example: ${example.path}` }; } }); } +let notesContent: string[] = []; +if (Array.isArray(funcNotes) && funcNotes.length > 0) { + notesContent = funcNotes; +} + ---
@@ -45,18 +53,36 @@ if ( funcExamples.length > 0 ){ title: func.id, tableOfContents: false, }}> + {funcPair && (

Pair: { funcPair }

)} - + {description && } - {funcExamples.length > 0 && funcExamples.map((example: any) => ( -
-

- + + {notesContent.length > 0 && ( +
+ {notesContent.map((note) => ( +
+ +
+ ))}
- ))} + )} + + + {processedExamples.length > 0 && ( +
+

Exemplos

+ {processedExamples.map((example: any) => ( +
+ + +
+ ))} +
+ )}
\ No newline at end of file diff --git a/web/src/styles/function-page.css b/web/src/styles/function-page.css new file mode 100644 index 00000000..3f5e1372 --- /dev/null +++ b/web/src/styles/function-page.css @@ -0,0 +1,39 @@ +.function-syntax, +.function-oop, +.notes-section, +.examples-section { + margin-top: 1.5rem; + margin-bottom: 1.5rem; +} + +.function-syntax h3, +.function-oop h3, +.examples-section h3 { + margin-bottom: 0.75rem; + font-size: 1.25em; + border-bottom: 1px solid var(--sl-color-gray-5); + padding-bottom: 0.25rem; +} + +.custom-note-box { + background-color: var(--sl-color-blue-low); + border-left: 4px solid var(--sl-color-blue); + border-radius: 8px; + padding: 1rem 1.25rem; + margin-bottom: 1rem; + color: var(--sl-color-text); +} + +html[data-theme="dark"] .custom-note-box { + background-color: var(--sl-color-gray-5); +} + +.function-example { + margin-bottom: 1.5rem; +} +.function-example > :first-child { + margin-bottom: 0.5rem; +} +.examples-section .function-example:last-child { + margin-bottom: 0; +} \ No newline at end of file diff --git a/web/src/utils/functions.ts b/web/src/utils/functions.ts index d5193cd1..302eeb5d 100644 --- a/web/src/utils/functions.ts +++ b/web/src/utils/functions.ts @@ -8,7 +8,7 @@ type FunctionItem = Awaited>[number]; // Define a structure for function parameters type FunctionParameter = { name: string; - type: string; // Adjust type as needed (e.g., string | string[]) + type: string; description?: string; optional?: boolean; }; @@ -19,6 +19,7 @@ type FunctionDetails = { pair?: boolean; examples?: { code: string; description?: string }[]; notes?: string[]; + important_notes?: string[]; parameters?: FunctionParameter[]; }; @@ -36,7 +37,6 @@ export type FunctionData = { server?: any; }; -// Use the specific FunctionDetails type export type TypedFunctionData = { shared?: FunctionDetails; client?: FunctionDetails; @@ -47,7 +47,7 @@ export const functionTypePrettyName = { 'client': 'Client-side', 'server': 'Server-side', 'shared': 'Shared', -} as const; // Use 'as const' for stricter typing of keys +} as const; function getFunctionType(data: FunctionData): FunctionType { if (data.shared) return 'shared'; @@ -55,25 +55,24 @@ function getFunctionType(data: FunctionData): FunctionType { return 'server'; } function getFunctionTypePretty(data: FunctionData): string { - // No need for fallback, getFunctionType guarantees a valid FunctionType const funcType = getFunctionType(data); return functionTypePrettyName[funcType]; } -// Define a return type for getFunctionInfo export type FunctionInfo = { description: string; type: FunctionType; typePretty: string; pair: boolean; examples: { code: string; description?: string }[]; - notes?: string[]; // Added notes - parameters?: FunctionParameter[]; // Added parameters + notes?: string[]; + important_notes?: string[]; + parameters?: FunctionParameter[]; }; export function getFunctionInfo(data: TypedFunctionData): FunctionInfo { const type = getFunctionType(data); - const details = data[type] ?? {}; // Get details based on type, default to empty object + const details = data[type] ?? {}; return { description: details.description || '', @@ -81,8 +80,9 @@ export function getFunctionInfo(data: TypedFunctionData): FunctionInfo { typePretty: getFunctionTypePretty(data), pair: details.pair || false, examples: details.examples || [], - notes: details.notes, // Extract notes (will be undefined if not present) - parameters: details.parameters || [], // Extract parameters + notes: details.notes || [], + important_notes: details.important_notes || [], + parameters: details.parameters || [], }; } @@ -95,8 +95,7 @@ let functionsByTypeByCategory: FunctionsByTypeByCategory = { }; for (let func of functionsCollection) { - // Assuming func.filePath exists, handle potential undefined if necessary - const normalizedPath = path.normalize(func.id); // Use func.id which includes the path relative to content dir + const normalizedPath = path.normalize(func.id); const folder = path.basename(path.dirname(normalizedPath)); if (!functionsByCategory[folder]) { functionsByCategory[folder] = []; @@ -104,7 +103,6 @@ for (let func of functionsCollection) { functionsByCategory[folder].push(func); const funcType = getFunctionType(func.data); - // Ensure the folder exists for the specific type if (!functionsByTypeByCategory[funcType]?.[folder]) { functionsByTypeByCategory[funcType][folder] = []; } From 0cd5b9acbd67a659709b69aa831288924899ea1c Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 5 May 2025 16:15:39 -0300 Subject: [PATCH 6/8] Add NoteBox component to display styled notes and remove notes section on functions page --- web/src/components/NoteBox.astro | 21 +++++++++++++++++++++ web/src/pages/[func].astro | 17 ++++++++--------- web/src/styles/function-page.css | 13 ------------- 3 files changed, 29 insertions(+), 22 deletions(-) create mode 100644 web/src/components/NoteBox.astro diff --git a/web/src/components/NoteBox.astro b/web/src/components/NoteBox.astro new file mode 100644 index 00000000..654cfc40 --- /dev/null +++ b/web/src/components/NoteBox.astro @@ -0,0 +1,21 @@ +--- +// Componente reutilizável para exibir uma caixa de nota estilizada. +// Ele usa um slot padrão para receber o conteúdo da nota. +--- +
+ {/* O conteúdo da nota será inserido aqui */} +
+ + \ No newline at end of file diff --git a/web/src/pages/[func].astro b/web/src/pages/[func].astro index 84c6b86f..067343ae 100644 --- a/web/src/pages/[func].astro +++ b/web/src/pages/[func].astro @@ -7,6 +7,7 @@ import fs from "fs"; import path from "path"; import { Code } from '@astrojs/starlight/components'; +import NoteBox from '@src/components/NoteBox.astro'; import '@src/styles/function-page.css'; export async function getStaticPaths() { @@ -62,15 +63,13 @@ if (Array.isArray(funcNotes) && funcNotes.length > 0) { {description && } - {notesContent.length > 0 && ( -
- {notesContent.map((note) => ( -
- -
- ))} -
- )} +
+ {notesContent.map((note) => ( + + + + ))} +
{processedExamples.length > 0 && ( diff --git a/web/src/styles/function-page.css b/web/src/styles/function-page.css index 3f5e1372..1c3e79b6 100644 --- a/web/src/styles/function-page.css +++ b/web/src/styles/function-page.css @@ -15,19 +15,6 @@ padding-bottom: 0.25rem; } -.custom-note-box { - background-color: var(--sl-color-blue-low); - border-left: 4px solid var(--sl-color-blue); - border-radius: 8px; - padding: 1rem 1.25rem; - margin-bottom: 1rem; - color: var(--sl-color-text); -} - -html[data-theme="dark"] .custom-note-box { - background-color: var(--sl-color-gray-5); -} - .function-example { margin-bottom: 1.5rem; } From 658785adc04ae691d387d35fa02bf8848ddbcd3c Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 5 May 2025 16:20:18 -0300 Subject: [PATCH 7/8] Refactor NoteBox component to use a custom element and clean up styling comments --- web/src/components/NoteBox.astro | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/web/src/components/NoteBox.astro b/web/src/components/NoteBox.astro index 654cfc40..81c4eae3 100644 --- a/web/src/components/NoteBox.astro +++ b/web/src/components/NoteBox.astro @@ -1,21 +1,19 @@ --- -// Componente reutilizável para exibir uma caixa de nota estilizada. -// Ele usa um slot padrão para receber o conteúdo da nota. --- -
- {/* O conteúdo da nota será inserido aqui */} -
+ + + \ No newline at end of file From bdb90cd1f2112db05bb9f2a6b2d80421897553a7 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 5 May 2025 16:23:26 -0300 Subject: [PATCH 8/8] Fix: bug where it called its own component recursively --- web/src/components/NoteBox.astro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/NoteBox.astro b/web/src/components/NoteBox.astro index 81c4eae3..0ba5baba 100644 --- a/web/src/components/NoteBox.astro +++ b/web/src/components/NoteBox.astro @@ -1,8 +1,8 @@ --- --- - +
- +