diff --git a/schemas/function.yaml b/schemas/function.yaml index 3cb22238..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. @@ -163,6 +171,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 diff --git a/web/src/components/NoteBox.astro b/web/src/components/NoteBox.astro new file mode 100644 index 00000000..0ba5baba --- /dev/null +++ b/web/src/components/NoteBox.astro @@ -0,0 +1,19 @@ +--- +--- +
+ +
+ + \ No newline at end of file diff --git a/web/src/pages/[func].astro b/web/src/pages/[func].astro index 6f3348a3..067343ae 100644 --- a/web/src/pages/[func].astro +++ b/web/src/pages/[func].astro @@ -7,6 +7,9 @@ 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() { const functions = await getCollection('functions'); return functions.map(func => ({ @@ -19,24 +22,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 ?? ""); -if ( funcExamples.length > 0 ){ - funcExamples = funcInfo.examples.map((example: any) => { +const { description, notes: funcNotes, examples: rawExamples } = funcInfo; + +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 +54,34 @@ if ( funcExamples.length > 0 ){ title: func.id, tableOfContents: false, }}> + {funcPair && ( -

Pair: { funcPair }

+

Pair: { funcPair }

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

- + + {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..1c3e79b6 --- /dev/null +++ b/web/src/styles/function-page.css @@ -0,0 +1,26 @@ +.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; +} + +.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 b75c7151..302eeb5d 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; + 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[]; + important_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; }; +export type TypedFunctionData = { + shared?: FunctionDetails; + client?: FunctionDetails; + server?: FunctionDetails; +}; + export const functionTypePrettyName = { 'client': 'Client-side', 'server': 'Server-side', 'shared': 'Shared', -}; +} as const; function getFunctionType(data: FunctionData): FunctionType { if (data.shared) return 'shared'; @@ -33,16 +56,33 @@ function getFunctionType(data: FunctionData): FunctionType { } function getFunctionTypePretty(data: FunctionData): string { const funcType = getFunctionType(data); - return functionTypePrettyName[funcType] ?? 'Server-side'; + return functionTypePrettyName[funcType]; } -export function getFunctionInfo(data: FunctionData): any { +export type FunctionInfo = { + description: string; + type: FunctionType; + typePretty: string; + pair: boolean; + examples: { code: string; description?: string }[]; + notes?: string[]; + important_notes?: string[]; + parameters?: FunctionParameter[]; +}; + +export function getFunctionInfo(data: TypedFunctionData): FunctionInfo { + const type = getFunctionType(data); + const details = data[type] ?? {}; + 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 || [], + important_notes: details.important_notes || [], + parameters: details.parameters || [], }; } @@ -55,7 +95,7 @@ let functionsByTypeByCategory: FunctionsByTypeByCategory = { }; for (let func of functionsCollection) { - const normalizedPath = path.normalize(func.filePath || ''); + const normalizedPath = path.normalize(func.id); const folder = path.basename(path.dirname(normalizedPath)); if (!functionsByCategory[folder]) { functionsByCategory[folder] = []; @@ -63,7 +103,7 @@ for (let func of functionsCollection) { functionsByCategory[folder].push(func); const funcType = getFunctionType(func.data); - if (!functionsByTypeByCategory[funcType][folder]) { + if (!functionsByTypeByCategory[funcType]?.[folder]) { functionsByTypeByCategory[funcType][folder] = []; } functionsByTypeByCategory[funcType][folder].push(func);