Skip to content

Add Notes Section #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
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
12 changes: 12 additions & 0 deletions schemas/function.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ $defs:
description:
type: string
description: Describes the functionality provided by the function.
important_notes:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think a new attribute is needed. You should change the notes attribute by giving it more properties other than description like "type" so we can specify the "importance" or color of the note (like warning).

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.
Expand Down Expand Up @@ -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:
Copy link
Collaborator

Choose a reason for hiding this comment

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

As I explained in the other PR #9 where you tried to implement this optional attribute, it is not needed.

type: boolean
default: false
description: If set to true, this parameter is optional.

returns:
type: object
Expand Down
19 changes: 19 additions & 0 deletions web/src/components/NoteBox.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
---
<div class="custom-note-box">
<slot />
</div >

<style>
.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);
}
</style>
57 changes: 41 additions & 16 deletions web/src/pages/[func].astro
Original file line number Diff line number Diff line change
Expand Up @@ -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 => ({
Expand All @@ -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;
}

---

<div class={"show-type-badge-" + funcType}>
Expand All @@ -45,18 +54,34 @@ if ( funcExamples.length > 0 ){
title: func.id,
tableOfContents: false,
}}>
<!-- Pair Function Ref -->
{funcPair && (
<p><strong>Pair:</strong> <a href={ funcPair }>{ funcPair }</a></p>
<p><strong>Pair:</strong> <a href={ `/${funcPair}` }>{ funcPair }</a></p>
)}

<!-- Description -->
<Fragment set:html={marked(funcInfo.description)} />
{description && <Fragment set:html={marked(description)} />}

<!-- Notes -->
<div class="notes-section">
{notesContent.map((note) => (
<NoteBox>
<Fragment set:html={marked(note)} />
</NoteBox>
))}
</div>

{funcExamples.length > 0 && funcExamples.map((example: any) => (
<div>
<p set:html={marked(example.description)}></p>
<Code code={example.luaCode} lang="lua" title={path.basename(example.path)} />
<!-- Examples -->
{processedExamples.length > 0 && (
<div class="examples-section">
<h3>Exemplos</h3>
{processedExamples.map((example: any) => (
<div class="function-example">
<Fragment set:html={marked(example.description)} />
<Code code={example.luaCode} lang="lua" title={path.basename(example.path)} />
</div>
))}
</div>
))}
)}
</StarlightPage>
</div>
26 changes: 26 additions & 0 deletions web/src/styles/function-page.css
Original file line number Diff line number Diff line change
@@ -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;
}
64 changes: 52 additions & 12 deletions web/src/utils/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,49 @@ import type { FunctionType } from './types';

type FunctionItem = Awaited<ReturnType<typeof getCollection>>[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';
Expand All @@ -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 || [],
};
}

Expand All @@ -55,15 +95,15 @@ 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] = [];
}
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);
Expand Down