From a3aefef7bf2ba422910337deaca543fc515852d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 12:16:40 +0000 Subject: [PATCH 1/6] Initial plan From 474c75805d852a33e391f27a61c82c11f2e08e0a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 12:24:26 +0000 Subject: [PATCH 2/6] Optimize GlossaryTable: pre-compute sanitized HTML in useMemo - Added `definitionHtml` field to DisplayEntry type - Compute sanitized HTML once when creating entries in useMemo - Use pre-computed HTML in render instead of calling sanitizeMarkdown on every render - This avoids re-parsing and re-sanitizing markdown on every render for every filtered entry Co-authored-by: Snooz82 <41592183+Snooz82@users.noreply.github.com> --- website/src/components/Glossary/GlossaryTable.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/website/src/components/Glossary/GlossaryTable.tsx b/website/src/components/Glossary/GlossaryTable.tsx index 2b1e63d..c05cd44 100644 --- a/website/src/components/Glossary/GlossaryTable.tsx +++ b/website/src/components/Glossary/GlossaryTable.tsx @@ -17,6 +17,7 @@ export type DisplayEntry = { term: string; abbreviation: string; definition: string; + definitionHtml: string; canonicalTerm: string; isAlias: boolean; slug: string; @@ -52,6 +53,7 @@ const GlossaryTable: React.FC = () => { term: item.term, abbreviation: item.abbreviation, definition: item.definition, + definitionHtml: sanitizeMarkdown(item.definition, purify), canonicalTerm: item.term, isAlias: false, slug, @@ -68,6 +70,7 @@ const GlossaryTable: React.FC = () => { term: alias, abbreviation: '', definition: `See ${item.term}`, + definitionHtml: '', // Alias entries don't need HTML since they use a link canonicalTerm: item.term, isAlias: true, slug: slugify(alias), @@ -82,7 +85,7 @@ const GlossaryTable: React.FC = () => { const combined = [...canonicalEntries, ...aliasEntries].sort((a, b) => a.term.localeCompare(b.term)); return { entries: combined, aliasToCanonicalSlug: aliasMap }; - }, []); + }, [purify]); const fuse = useMemo( () => @@ -202,7 +205,6 @@ const GlossaryTable: React.FC = () => { {filteredEntries.map((entry) => { - const definitionHtml = sanitizeMarkdown(entry.definition, purify); const handleClick = () => focusEntry(entry.targetSlug, entry.canonicalTerm); return ( @@ -245,7 +247,7 @@ const GlossaryTable: React.FC = () => { <>
{entry.abbreviation ? ( From 22ee2c0f13cb910a8e45824a1d3977c4b6331490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rene=CC=81?= Date: Sun, 7 Dec 2025 13:48:58 +0100 Subject: [PATCH 3/6] fixed comment from Copilot Review --- .../src/components/Glossary/GlossaryTable.tsx | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/website/src/components/Glossary/GlossaryTable.tsx b/website/src/components/Glossary/GlossaryTable.tsx index c05cd44..17cbd26 100644 --- a/website/src/components/Glossary/GlossaryTable.tsx +++ b/website/src/components/Glossary/GlossaryTable.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import Fuse from 'fuse.js'; import clsx from 'clsx'; import { marked } from 'marked'; @@ -31,29 +31,34 @@ const slugify = (text: string): string => .replace(/[^a-z0-9]+/g, '-') .replace(/(^-+|-+$)/g, ''); -const sanitizeMarkdown = (markdown: string, purify: typeof DOMPurify | null): string => { - const html = marked.parse(markdown || '', { async: false }) as string; - return purify ? purify.sanitize(html) : html; -}; - const GlossaryTable: React.FC = () => { const [termQuery, setTermQuery] = useState(''); const [textQuery, setTextQuery] = useState(''); const [activeSlug, setActiveSlug] = useState(''); + const [entries, setEntries] = useState([]); + const [aliasToCanonicalSlug, setAliasToCanonicalSlug] = useState>(new Map()); + const purifyRef = useRef(null); + const [purifyReady, setPurifyReady] = useState(false); - const purify = useMemo(() => (typeof window === 'undefined' ? null : DOMPurify), []); + useEffect(() => { + if (typeof window !== 'undefined') { + purifyRef.current = DOMPurify; + setPurifyReady(true); + } + }, []); - const { entries, aliasToCanonicalSlug } = useMemo(() => { + useEffect(() => { const glossaryItems = glossaryData as GlossaryItem[]; const termSet = new Set(glossaryItems.map((item) => item.term)); const canonicalEntries: DisplayEntry[] = glossaryItems.map((item) => { const slug = slugify(item.term); + const html = marked.parse(item.definition || '', { async: false }) as string; return { term: item.term, abbreviation: item.abbreviation, definition: item.definition, - definitionHtml: sanitizeMarkdown(item.definition, purify), + definitionHtml: html, canonicalTerm: item.term, isAlias: false, slug, @@ -70,7 +75,7 @@ const GlossaryTable: React.FC = () => { term: alias, abbreviation: '', definition: `See ${item.term}`, - definitionHtml: '', // Alias entries don't need HTML since they use a link + definitionHtml: '', canonicalTerm: item.term, isAlias: true, slug: slugify(alias), @@ -84,8 +89,19 @@ const GlossaryTable: React.FC = () => { aliasEntries.forEach((entry) => aliasMap.set(entry.slug, entry.targetSlug)); const combined = [...canonicalEntries, ...aliasEntries].sort((a, b) => a.term.localeCompare(b.term)); - return { entries: combined, aliasToCanonicalSlug: aliasMap }; - }, [purify]); + setEntries(combined); + setAliasToCanonicalSlug(aliasMap); + }, []); + + useEffect(() => { + if (!purifyReady || !purifyRef.current) return; + setEntries((prev) => + prev.map((entry) => { + if (entry.isAlias || !entry.definitionHtml) return entry; + return { ...entry, definitionHtml: purifyRef.current!.sanitize(entry.definitionHtml) }; + }) + ); + }, [purifyReady]); const fuse = useMemo( () => From 9c04748233c2773944e1b85400d8a90d5667d4ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9?= <41592183+Snooz82@users.noreply.github.com> Date: Sun, 7 Dec 2025 13:55:17 +0100 Subject: [PATCH 4/6] Update website/src/components/Glossary/GlossaryTable.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- website/src/components/Glossary/GlossaryTable.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/website/src/components/Glossary/GlossaryTable.tsx b/website/src/components/Glossary/GlossaryTable.tsx index 17cbd26..4badb52 100644 --- a/website/src/components/Glossary/GlossaryTable.tsx +++ b/website/src/components/Glossary/GlossaryTable.tsx @@ -54,11 +54,15 @@ const GlossaryTable: React.FC = () => { const canonicalEntries: DisplayEntry[] = glossaryItems.map((item) => { const slug = slugify(item.term); const html = marked.parse(item.definition || '', { async: false }) as string; + const sanitizedHtml = + typeof window !== 'undefined' && purifyRef.current + ? purifyRef.current.sanitize(html) + : html; return { term: item.term, abbreviation: item.abbreviation, definition: item.definition, - definitionHtml: html, + definitionHtml: sanitizedHtml, canonicalTerm: item.term, isAlias: false, slug, From f05b1164665c6088b1c58bfe40238a012f4cea7c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 12:59:37 +0000 Subject: [PATCH 5/6] Simplify GlossaryTable: revert to useMemo approach - Removed unnecessary state variables (entries, aliasToCanonicalSlug, purifyRef, purifyReady) - Reverted to useMemo for derived values from static glossaryData - Removed redundant useEffects that caused race conditions and extra re-renders - Simplified sanitizeMarkdown function to check window directly - Maintains security by sanitizing on client, unsanitized on SSR (original behavior) Co-authored-by: Snooz82 <41592183+Snooz82@users.noreply.github.com> --- website/docusaurus.config.js | 178 +++++++++++++++ website/sidebars.js | 30 +++ .../src/components/Glossary/GlossaryTable.js | 214 ++++++++++++++++++ .../src/components/Glossary/GlossaryTable.tsx | 42 +--- .../src/components/HomepageFeatures/index.js | 79 +++++++ website/src/components/Quiz/Quiz.js | 14 ++ website/src/components/Quiz/QuizComponent.js | 182 +++++++++++++++ website/src/components/Quiz/QuizStore.js | 50 ++++ website/src/components/Quiz/quizComponents.js | 20 ++ website/src/components/Quiz/quizComponents.ts | 2 +- .../components/Quiz/resultPage/resultCard.js | 56 +++++ .../src/components/Quiz/resultPage/sidebar.js | 39 ++++ website/src/components/Term.js | 141 ++++++++++++ website/src/pages/index.js | 42 ++++ website/src/theme/Admonition/index.js | 49 ++++ website/src/theme/MDXComponents.js | 16 ++ 16 files changed, 1121 insertions(+), 33 deletions(-) create mode 100644 website/docusaurus.config.js create mode 100644 website/sidebars.js create mode 100644 website/src/components/Glossary/GlossaryTable.js create mode 100644 website/src/components/HomepageFeatures/index.js create mode 100644 website/src/components/Quiz/Quiz.js create mode 100644 website/src/components/Quiz/QuizComponent.js create mode 100644 website/src/components/Quiz/QuizStore.js create mode 100644 website/src/components/Quiz/quizComponents.js create mode 100644 website/src/components/Quiz/resultPage/resultCard.js create mode 100644 website/src/components/Quiz/resultPage/sidebar.js create mode 100644 website/src/components/Term.js create mode 100644 website/src/pages/index.js create mode 100644 website/src/theme/Admonition/index.js create mode 100644 website/src/theme/MDXComponents.js diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js new file mode 100644 index 0000000..7e2a508 --- /dev/null +++ b/website/docusaurus.config.js @@ -0,0 +1,178 @@ +"use strict"; +// @ts-check +// Note: type annotations allow type checking and IDEs autocompletion +Object.defineProperty(exports, "__esModule", { value: true }); +var lightCodeTheme = require('prism-react-renderer').themes.vsLight; +var darkCodeTheme = require('prism-react-renderer').themes.dracula; +var remark_directive_1 = require("remark-directive"); +var remark_term_directive_js_1 = require("./src/remark/remark-term-directive.js"); +var remark_code_max_line_length_js_1 = require("./src/remark/remark-code-max-line-length.js"); +/** @type {import('@docusaurus/types').Config} */ +var config = { + title: 'Syllabus of Robot Framework® Certified Professional', + tagline: 'The foundation for the "Robot Framework® Certified Professional" (RFCP®) exam and training', + url: 'https://robotframework.org', + baseUrl: '/robotframework-RFCP-syllabus/', + onBrokenLinks: 'throw', + markdown: { + hooks: { + onBrokenMarkdownLinks: 'throw', + }, + }, + favicon: 'img/rf_favicon.png', + organizationName: 'robotframework', // Usually your GitHub org/user name. + projectName: 'robotframework-RFCP-syllabus', // Usually your repo name. + trailingSlash: false, + presets: [ + [ + 'classic', + /** @type {import('@docusaurus/preset-classic').Options} */ + ({ + docs: { + admonitions: { + keywords: ['lo', 'K1', 'K2', 'K3', 'note', 'tip', 'info', 'warning', 'danger'], + extendDefaults: true, + }, + routeBasePath: '/docs', + sidebarPath: require.resolve('./sidebars.js'), + // Please change this to your repo. + // editUrl: 'https://github.com/robotframework/robotframework-RFCP-syllabus/edit/docusaurus/website', + remarkPlugins: [remark_directive_1.default, remark_term_directive_js_1.default, [remark_code_max_line_length_js_1.default, { max: 100 }]], + }, + blog: false, + theme: { + customCss: require.resolve('./src/css/custom.css'), + }, + }), + ], + ], + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + ({ + colorMode: { + defaultMode: 'dark', + disableSwitch: false, + respectPrefersColorScheme: false, + }, + navbar: { + title: 'RFCP-Syllabus', + logo: { + alt: 'Robot Framework Logo', + src: 'img/robot-framework.svg', + srcDark: 'img/robot-framework-dark.svg', + }, + items: [ + { + label: 'Introduction', + to: '/docs/overview', + position: 'left', + }, + { + label: 'Chapter 1', + to: '/docs/chapter-01/overview', + position: 'left', + }, + { + label: 'Chapter 2', + to: '/docs/chapter-02/overview', + position: 'left', + }, + { + label: 'Chapter 3', + to: '/docs/chapter-03/overview', + position: 'left', + }, + { + label: 'Chapter 4', + to: '/docs/chapter-04/overview', + position: 'left', + }, + { + label: 'Chapter 5', + to: '/docs/chapter-05/overview', + position: 'left', + }, + { + label: 'Example Exam', + to: '/docs/example-exam', + position: 'left', + }, + { + label: 'LOs', + to: '/docs/learning_objectives', + position: 'left', + }, + // { + // href: 'https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html', + // label: 'User Guide', + // position: 'right', + // }, + // { + // href: 'https://robotframework.org/robotframework/#standard-libraries', + // label: 'Standard Library', + // position: 'right', + // }, + // { + // href: 'https://robot-framework.readthedocs.io/en/stable/', + // label: 'API Documentation', + // position: 'right', + // }, + // { + // href: 'https://slack.robotframework.org/', + // label: 'Slack', + // position: 'right', + // }, + // { + // href: 'https://github.com/robotframework/robotframework-RFCP-syllabus', + // label: 'GitHub', + // position: 'right', + // }, + ], + }, + footer: { + style: 'dark', + links: [ + // { + // title: 'Docs', + // items: [ + // { + // label: 'Syllabus', + // to: '/docs/overview', + // }, + // // { + // // href: 'https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html', + // // label: 'User Guide', + // // }, + // // { + // // href: 'https://robotframework.org/robotframework/#standard-libraries', + // // label: 'Standard Library', + // // }, + // // { + // // href: 'https://robot-framework.readthedocs.io/en/stable/', + // // label: 'API Documentation', + // // }, + // ], + // }, + // { + // title: 'More', + // items: [ + // { + // label: 'GitHub', + // href: 'https://github.com/robotframework/robotframework-RFCP-syllabus', + // }, + // ], + // }, + ], + copyright: "Copyright \u00A9 ".concat(new Date().getFullYear(), " Robot Framework\u00AE Foundation - Syllabus of Robot Framework\u00AE Certified Professional"), + }, + prism: { + theme: lightCodeTheme, + darkTheme: darkCodeTheme, + additionalLanguages: ['robotframework', 'python'], + }, + }), + plugins: [ + require.resolve('docusaurus-lunr-search') + ], +}; +module.exports = config; diff --git a/website/sidebars.js b/website/sidebars.js new file mode 100644 index 0000000..934c233 --- /dev/null +++ b/website/sidebars.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ +var sidebars = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], + // But you can create a sidebar manually + /* + tutorialSidebar: [ + 'intro', + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], + */ +}; +exports.default = sidebars; diff --git a/website/src/components/Glossary/GlossaryTable.js b/website/src/components/Glossary/GlossaryTable.js new file mode 100644 index 0000000..a603424 --- /dev/null +++ b/website/src/components/Glossary/GlossaryTable.js @@ -0,0 +1,214 @@ +"use strict"; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var react_1 = require("react"); +var fuse_js_1 = require("fuse.js"); +var clsx_1 = require("clsx"); +var marked_1 = require("marked"); +var dompurify_1 = require("dompurify"); +var glossary_json_1 = require("@site/static/glossary/glossary.json"); +var GlossaryTable_module_css_1 = require("./GlossaryTable.module.css"); +var slugify = function (text) { + return text + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/(^-+|-+$)/g, ''); +}; +var sanitizeMarkdown = function (markdown) { + var html = marked_1.marked.parse(markdown || '', { async: false }); + return typeof window !== 'undefined' ? dompurify_1.default.sanitize(html) : html; +}; +var GlossaryTable = function () { + var _a = (0, react_1.useState)(''), termQuery = _a[0], setTermQuery = _a[1]; + var _b = (0, react_1.useState)(''), textQuery = _b[0], setTextQuery = _b[1]; + var _c = (0, react_1.useState)(''), activeSlug = _c[0], setActiveSlug = _c[1]; + var _d = (0, react_1.useMemo)(function () { + var glossaryItems = glossary_json_1.default; + var termSet = new Set(glossaryItems.map(function (item) { return item.term; })); + var canonicalEntries = glossaryItems.map(function (item) { + var slug = slugify(item.term); + return { + term: item.term, + abbreviation: item.abbreviation, + definition: item.definition, + definitionHtml: sanitizeMarkdown(item.definition), + canonicalTerm: item.term, + isAlias: false, + slug: slug, + targetSlug: slug, + aliases: item.aliases || [], + }; + }); + var aliasEntries = glossaryItems.flatMap(function (item) { + var canonicalSlug = slugify(item.term); + return (item.aliases || []) + .filter(function (alias) { return !termSet.has(alias); }) + .map(function (alias) { return ({ + term: alias, + abbreviation: '', + definition: "See ".concat(item.term), + definitionHtml: '', // Alias entries don't need HTML since they use a link + canonicalTerm: item.term, + isAlias: true, + slug: slugify(alias), + targetSlug: canonicalSlug, + aliases: [], + }); }); + }); + var aliasMap = new Map(); + canonicalEntries.forEach(function (entry) { return aliasMap.set(entry.slug, entry.targetSlug); }); + aliasEntries.forEach(function (entry) { return aliasMap.set(entry.slug, entry.targetSlug); }); + var combined = __spreadArray(__spreadArray([], canonicalEntries, true), aliasEntries, true).sort(function (a, b) { return a.term.localeCompare(b.term); }); + return { entries: combined, aliasToCanonicalSlug: aliasMap }; + }, []), entries = _d.entries, aliasToCanonicalSlug = _d.aliasToCanonicalSlug; + var fuse = (0, react_1.useMemo)(function () { + return new fuse_js_1.default(entries, { + keys: [ + { name: 'term', weight: 0.5 }, + { name: 'definition', weight: 0.4 }, + { name: 'abbreviation', weight: 0.1 }, + { name: 'aliases', weight: 0.3 }, + ], + threshold: 0.35, + ignoreLocation: true, + }); + }, [entries]); + var focusEntry = (0, react_1.useCallback)(function (slug, canonicalTerm) { + if (!slug || typeof window === 'undefined') { + return; + } + var targetSlug = slug; + setActiveSlug(targetSlug); + var url = new URL(window.location.href); + url.hash = targetSlug; + if (canonicalTerm) { + url.searchParams.set('term', canonicalTerm); + } + else { + url.searchParams.set('term', targetSlug); + } + window.history.replaceState({}, '', url.toString()); + var target = document.getElementById(targetSlug); + if (target) { + var top_1 = target.getBoundingClientRect().top + window.scrollY - 70; // account for sticky header + window.scrollTo({ top: top_1, behavior: 'smooth' }); + } + }, []); + (0, react_1.useEffect)(function () { + if (typeof window === 'undefined') { + return; + } + var params = new URLSearchParams(window.location.search); + var termParam = params.get('term'); + var hashParam = window.location.hash ? window.location.hash.replace('#', '') : ''; + var rawSlug = hashParam || (termParam ? slugify(termParam) : ''); + var initialSlug = aliasToCanonicalSlug.get(rawSlug) || rawSlug; + if (initialSlug) { + setActiveSlug(initialSlug); + // Allow the page to render before scrolling + setTimeout(function () { return focusEntry(initialSlug, termParam || initialSlug); }, 50); + } + }, [aliasToCanonicalSlug, focusEntry]); + var filteredEntries = (0, react_1.useMemo)(function () { + var normalize = function (value) { return value.toLowerCase(); }; + var subset = entries; + if (termQuery.trim()) { + var query_1 = normalize(termQuery.trim()); + subset = subset.filter(function (entry) { + return (normalize(entry.term).includes(query_1) || + normalize(entry.canonicalTerm).includes(query_1) || + (entry.aliases || []).some(function (alias) { return normalize(alias).includes(query_1); })); + }); + } + if (textQuery.trim()) { + var results = fuse.search(textQuery.trim()); + var allowedSlugs_1 = new Set(); + results.forEach(function (_a) { + var item = _a.item; + return allowedSlugs_1.add(item.slug); + }); + subset = subset.filter(function (entry) { return allowedSlugs_1.has(entry.slug); }); + } + return subset; + }, [entries, fuse, termQuery, textQuery]); + return (
+
+ + +
+ +
+ + + + + + + + + {filteredEntries.map(function (entry) { + var _a; + var handleClick = function () { return focusEntry(entry.targetSlug, entry.canonicalTerm); }; + return ( + + + ); + })} + +
TermDefinition & Abbreviation
+
{entry.term}
+
+ {entry.isAlias ? ( + // Hyperlink to term in alias definition cell + + See {entry.canonicalTerm} + ) : (<> +
+
+ {entry.abbreviation ? ( + {entry.abbreviation} + ) : null} + {(entry.aliases || []).map(function (alias) { + var aliasSlug = slugify(alias); + var target = aliasToCanonicalSlug.get(aliasSlug) || aliasSlug; + return ( + // Link to alias term + + {alias} + ); + })} +
+ )} +
+
+
); +}; +exports.default = GlossaryTable; diff --git a/website/src/components/Glossary/GlossaryTable.tsx b/website/src/components/Glossary/GlossaryTable.tsx index 4badb52..24a1d8c 100644 --- a/website/src/components/Glossary/GlossaryTable.tsx +++ b/website/src/components/Glossary/GlossaryTable.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import Fuse from 'fuse.js'; import clsx from 'clsx'; import { marked } from 'marked'; @@ -31,38 +31,27 @@ const slugify = (text: string): string => .replace(/[^a-z0-9]+/g, '-') .replace(/(^-+|-+$)/g, ''); +const sanitizeMarkdown = (markdown: string): string => { + const html = marked.parse(markdown || '', { async: false }) as string; + return typeof window !== 'undefined' ? DOMPurify.sanitize(html) : html; +}; + const GlossaryTable: React.FC = () => { const [termQuery, setTermQuery] = useState(''); const [textQuery, setTextQuery] = useState(''); const [activeSlug, setActiveSlug] = useState(''); - const [entries, setEntries] = useState([]); - const [aliasToCanonicalSlug, setAliasToCanonicalSlug] = useState>(new Map()); - const purifyRef = useRef(null); - const [purifyReady, setPurifyReady] = useState(false); - useEffect(() => { - if (typeof window !== 'undefined') { - purifyRef.current = DOMPurify; - setPurifyReady(true); - } - }, []); - - useEffect(() => { + const { entries, aliasToCanonicalSlug } = useMemo(() => { const glossaryItems = glossaryData as GlossaryItem[]; const termSet = new Set(glossaryItems.map((item) => item.term)); const canonicalEntries: DisplayEntry[] = glossaryItems.map((item) => { const slug = slugify(item.term); - const html = marked.parse(item.definition || '', { async: false }) as string; - const sanitizedHtml = - typeof window !== 'undefined' && purifyRef.current - ? purifyRef.current.sanitize(html) - : html; return { term: item.term, abbreviation: item.abbreviation, definition: item.definition, - definitionHtml: sanitizedHtml, + definitionHtml: sanitizeMarkdown(item.definition), canonicalTerm: item.term, isAlias: false, slug, @@ -79,7 +68,7 @@ const GlossaryTable: React.FC = () => { term: alias, abbreviation: '', definition: `See ${item.term}`, - definitionHtml: '', + definitionHtml: '', // Alias entries don't need HTML since they use a link canonicalTerm: item.term, isAlias: true, slug: slugify(alias), @@ -93,20 +82,9 @@ const GlossaryTable: React.FC = () => { aliasEntries.forEach((entry) => aliasMap.set(entry.slug, entry.targetSlug)); const combined = [...canonicalEntries, ...aliasEntries].sort((a, b) => a.term.localeCompare(b.term)); - setEntries(combined); - setAliasToCanonicalSlug(aliasMap); + return { entries: combined, aliasToCanonicalSlug: aliasMap }; }, []); - useEffect(() => { - if (!purifyReady || !purifyRef.current) return; - setEntries((prev) => - prev.map((entry) => { - if (entry.isAlias || !entry.definitionHtml) return entry; - return { ...entry, definitionHtml: purifyRef.current!.sanitize(entry.definitionHtml) }; - }) - ); - }, [purifyReady]); - const fuse = useMemo( () => new Fuse(entries, { diff --git a/website/src/components/HomepageFeatures/index.js b/website/src/components/HomepageFeatures/index.js new file mode 100644 index 0000000..346715e --- /dev/null +++ b/website/src/components/HomepageFeatures/index.js @@ -0,0 +1,79 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = HomepageFeatures; +var clsx_1 = require("clsx"); +var Heading_1 = require("@theme/Heading"); +var styles_module_css_1 = require("./styles.module.css"); +var Link_1 = require("@docusaurus/Link"); +var FeatureList = [ + { + title: '0. About the Syllabus', + description: (<> + This chapter provides an overview of the Robot Framework® Certified Professional (RFCP®) syllabus, + detailing the course structure, learning objectives, and the foundational knowledge required for certification. + ), + link: '/docs/overview', + }, + { + title: '1. Introduction to Robot Framework', + description: (<> + This chapter introduces Robot Framework, detailing its primary use cases, + its architecture, core components, specification styles, and introduces the Robot Framework Foundation. + ), + link: '/docs/chapter-01/overview', + }, + { + title: '2. Getting Started with Robot Framework', + description: (<> + This chapter introduces the foundational concepts of Robot Framework, + execution processes, the utilization of libraries and resource files, + how to read keyword documentation, and how to write first tests. + ), + link: '/docs/chapter-02/overview', + }, + { + title: '3. Keyword Design, Variables, and Resource Files', + description: (<> + This chapter delves into the essential components of + Robot Framework, such as **Variables**, **User Keywords**, **Resource Files**, + and Data-Driven Testing. + ), + link: '/docs/chapter-03/overview', + }, + { + title: '4. Advanced Structuring and Execution', + description: (<> + This chapter delves into advanced techniques for structuring + and executing Robot Framework, explaining the use of + **Setups** and **Teardowns**, and the application of tags + to efficiently filter and control execution. + ), + link: '/docs/chapter-04/overview', + }, + { + title: '5. Exploring Advanced Constructs', + description: (<> + This chapter introduces advanced constructs in Robot Framework, + such as advanced variable handling and control structures like IF and FOR statements. + ), + link: '/docs/chapter-05/overview', + } +]; +function Feature(_a) { + var title = _a.title, description = _a.description, link = _a.link; + return ( +
+ {title} +

{description}

+
+
); +} +function HomepageFeatures() { + return (
+
+
+ {FeatureList.map(function (props, idx) { return (); })} +
+
+
); +} diff --git a/website/src/components/Quiz/Quiz.js b/website/src/components/Quiz/Quiz.js new file mode 100644 index 0000000..f6ef29c --- /dev/null +++ b/website/src/components/Quiz/Quiz.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = QuizLoader; +var react_1 = require("react"); +var ExecutionEnvironment_1 = require("@docusaurus/ExecutionEnvironment"); +var QuizComponent = react_1.default.lazy(function () { return Promise.resolve().then(function () { return require('./QuizComponent'); }); }); +function QuizLoader(_a) { + var name = _a.name, question = _a.question, src = _a.src; + if (!ExecutionEnvironment_1.default.canUseDOM) + return null; + return (Loading Quiz...
}> + + ); +} diff --git a/website/src/components/Quiz/QuizComponent.js b/website/src/components/Quiz/QuizComponent.js new file mode 100644 index 0000000..e9384ad --- /dev/null +++ b/website/src/components/Quiz/QuizComponent.js @@ -0,0 +1,182 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); + return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = Quiz; +var react_1 = require("react"); +var ExecutionEnvironment_1 = require("@docusaurus/ExecutionEnvironment"); +var github_light_1 = require("@shikijs/themes/github-light"); +var dracula_1 = require("@shikijs/themes/dracula"); +var quizdown_es_js_1 = require("quizdown-extended/dist/quizdown.es.js"); +var QuizStore_1 = require("./QuizStore"); +require("./Quiz.css"); +var python_1 = require("@shikijs/langs/python"); +var robotframework_tmLanguage_json_1 = require("./robotframework-tmLanguage.json"); +function Quiz(_a) { + var _this = this; + var name = _a.name, question = _a.question, src = _a.src; + var addQuizResult = (0, QuizStore_1.default)(function (state) { return state.addQuizResult; }); + // const resultBaseUrl = useBaseUrl('/quizResults'); + var _b = (0, react_1.useState)(question || null), content = _b[0], setContent = _b[1]; + var generateQuizId = function (name) { + var page = typeof window !== 'undefined' ? window.location.pathname : ''; + page = page.replace('/robotframework-RFCP-syllabus/', ''); + var id = page.replace('docs/', '').replace('/', '_').replace('-', '_') + '_' + name.replace(' ', '_'); + return id.toLocaleLowerCase(); + }; + var genQuizId = function () { + if (ExecutionEnvironment_1.default.canUseDOM) { + return generateQuizId(name); + } + return 'quiz-id'; + }; + // const generateResultLink = () => { + // if (ExecutionEnvironment.canUseDOM) { + // return resultBaseUrl + '#' + generateQuizId(name); + // } + // return '#'; + // }; + // Load quiz content from external file if src is provided + (0, react_1.useEffect)(function () { + if (!src) + return; + fetch('/robotframework-RFCP-syllabus/quizzes/' + src) + .then(function (res) { + if (!res.ok) + throw new Error("Failed to fetch quiz: ".concat(res.status)); + return res.text(); + }) + .then(function (text) { + setContent(text); + }) + .catch(function (err) { + console.error('Error loading quiz:', err); + }); + }, [src, name]); + (0, react_1.useEffect)(function () { + if (!ExecutionEnvironment_1.default.canUseDOM || !content) { + return; + } + // Set CSS variables for component colors (existing) + document.documentElement.style.setProperty('--quizdownPrimaryColor', 'var(--quizdown-color-primary)'); + document.documentElement.style.setProperty('--quizdownSecondaryColor', 'var(--quizdown-color-secondary)'); + document.documentElement.style.setProperty('--quizdownTextColor', 'var(--quizdown-color-text)'); + document.documentElement.style.setProperty('--quizdownButtonColor', 'var(--quizdown-color-button)'); + document.documentElement.style.setProperty('--quizdownColorShadow', 'var(--quizdown-color-shadow)'); + document.documentElement.style.setProperty('--quizdownBackgroundColor', 'var(--quizdown-color-background, var(--ifm-navbar-background-color))'); + document.documentElement.style.setProperty('--quizdownColorHint', 'var(--quizdown-color-hint)'); + document.documentElement.style.setProperty('--quizdownColorHintBg', 'var(--quizdown-color-hint-bg)'); + document.documentElement.style.setProperty('--quizdownColorPass', 'var(--quizdown-color-pass)'); + document.documentElement.style.setProperty('--quizdownColorPassBg', 'var(--quizdown-color-pass-bg)'); + document.documentElement.style.setProperty('--quizdownColorFail', 'var(--quizdown-color-fail)'); + document.documentElement.style.setProperty('--quizdownColorFailBg', 'var(--quizdown-color-fail-bg)'); + document.documentElement.style.setProperty('--quizdownColorCodeBg', 'var(--quizdown-color-code-bg)'); + var node = document.querySelector('#' + genQuizId()); + if (!node) { + console.error("[Quiz:".concat(name, "] Could not find #").concat(genQuizId())); + return; + } + var quizdown = new quizdown_es_js_1.default(); + // this.hintSymbolColor = get(options['hintSymbolColor'], '#ff9800'); + // this.hintBgColor = get(options['hintBgColor'], '#ff990040'); + // this.passSymbolColor = get(options['passSymbolColor'], '#00cc88'); + // this.passBgColor = get(options['passBgColor'], '#00cc8840'); + // this.failSymbolColor = get(options['failSymbolColor'], '#e72323'); + // this.failBgColor = get(options['failBgColor'], '#e7232340'); + // this.infoSymbolColor = get(options['infoSymbolColor'], '#2196F3'); + // this.submitSymbolColor = get(options['submitSymbolColor'], '#2196F3'); + // + var config = { + startOnLoad: true, + shuffleAnswers: true, + shuffleQuestions: true, + nQuestions: undefined, + primaryColor: 'var(--quizdownPrimaryColor)', + secondaryColor: 'var(--quizdownSecondaryColor)', + textColor: 'var(--quizdownTextColor)', + buttonColor: 'var(--quizdownButtonColor)', + shadowColor: 'var(--quizdownColorShadow)', + backgroundColor: 'var(--quizdownBackgroundColor)', + hintSymbolColor: 'var(--quizdownColorHint)', + hintBgColor: 'var(--quizdownColorHintBg)', + passSymbolColor: 'var(--quizdownColorPass)', + passBgColor: 'var(--quizdownColorPassBg)', + failSymbolColor: 'var(--quizdownColorFail)', + failBgColor: 'var(--quizdownColorFailBg)', + codeBgColor: 'var(--quizdownColorCodeBg)', + locale: 'en', + enableRetry: true, + // NEW: Font configuration (requires updated quizdown files) + fontFamilyHeading: 'Roboto, sans-serif', + //'var(--ifm-font-family-heading)', + // NEW: Custom styles to match Docusaurus + customStyles: "\n .quizdown-content {\n font-size: var(--ifm-font-size-base, 16px);\n line-height: var(--ifm-line-height-base, 1.65);\n }\n " + }; + quizdown.createApp(content, node, config); + // quizdown.hooks.onQuizFinish((event) => { + // addQuizResult( + // generateQuizId(name), + // event.numberOfQuestions, + // event.solved, + // event.right, + // event.wrong + // ); + // }); + quizdown.getShikiInstance().then(function (instance) { return __awaiter(_this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, quizdown.registerShikiLanguage(python_1.default)]; + case 1: + _a.sent(); + return [4 /*yield*/, quizdown.registerShikiLanguage(robotframework_tmLanguage_json_1.default)]; + case 2: + _a.sent(); + return [4 /*yield*/, quizdown.registerShikiTheme('light', 'light', github_light_1.default)]; + case 3: + _a.sent(); + return [4 /*yield*/, quizdown.registerShikiTheme('dark', 'dark', dracula_1.default)]; + case 4: + _a.sent(); + return [2 /*return*/]; + } + }); + }); }); + }, [content, name]); + return ( + + ); +} diff --git a/website/src/components/Quiz/QuizStore.js b/website/src/components/Quiz/QuizStore.js new file mode 100644 index 0000000..e1b100d --- /dev/null +++ b/website/src/components/Quiz/QuizStore.js @@ -0,0 +1,50 @@ +"use strict"; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var zustand_1 = require("zustand"); +var middleware_1 = require("zustand/middleware"); +// Create the store +var useQuizStore = (0, zustand_1.create)()((0, middleware_1.persist)(function (set, get) { return ({ + quiz: [], + // Action to add a new quiz + addQuizResult: function (quizId, numberOfQuestions, solved, right, wrong) { + var state = get(); + var id = self.crypto.randomUUID(); + ; + var timestamp = new Date().toISOString(); + // Otherwise add the new quiz + set({ + quiz: __spreadArray(__spreadArray([], state.quiz, true), [ + { + id: id, + quizId: quizId, + timestamp: timestamp, + results: { + numberOfQuestions: numberOfQuestions, + solved: solved, + right: right, + wrong: wrong, + } + } + ], false) + }); + return id; + }, + getQuizResults: function (quizId) { + var state = get(); + return state.quiz.filter(function (value) { + return value.quizId === quizId; + }); + } +}); }, { + name: 'quiz-results', // unique name for localStorage +})); +exports.default = useQuizStore; diff --git a/website/src/components/Quiz/quizComponents.js b/website/src/components/Quiz/quizComponents.js new file mode 100644 index 0000000..a6e087a --- /dev/null +++ b/website/src/components/Quiz/quizComponents.js @@ -0,0 +1,20 @@ +"use strict"; +/* +* This file is automatically generated and will be overridden when running the build process. +* Generated on: 12/5/2025, 1:04:36 PM +*/ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.quizPages = void 0; +exports.quizPages = [ + { + "id": "docs-example-exam", + "name": "example-exam", + "quizzes": [ + { + "id": "example-exam#example", + "name": "Example", + "src": "Example.md" + } + ] + } +]; diff --git a/website/src/components/Quiz/quizComponents.ts b/website/src/components/Quiz/quizComponents.ts index 21b28d0..c2380a7 100644 --- a/website/src/components/Quiz/quizComponents.ts +++ b/website/src/components/Quiz/quizComponents.ts @@ -1,6 +1,6 @@ /* * This file is automatically generated and will be overridden when running the build process. -* Generated on: 12/5/2025, 1:04:36 PM +* Generated on: 12/7/2025, 12:57:51 PM */ export interface QuizPage { diff --git a/website/src/components/Quiz/resultPage/resultCard.js b/website/src/components/Quiz/resultPage/resultCard.js new file mode 100644 index 0000000..2835790 --- /dev/null +++ b/website/src/components/Quiz/resultPage/resultCard.js @@ -0,0 +1,56 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var react_1 = require("react"); +require("./resultCard.css"); +var QuizResultCard = function (props) { + // Calculate success rate + var successRate = Math.round((props.result.results.right / props.result.results.numberOfQuestions) * 100); + // Format timestamp to a more readable format + var formatTimestamp = function (timestamp) { + try { + var date = new Date(timestamp); + return date.toLocaleString(); + } + catch (e) { + return timestamp; + } + }; + return (
+
+

{formatTimestamp(props.result.timestamp)}

+ +
+ +
+
+
+ {successRate}% +
+
+
+ Right: + {props.result.results.right} +
+
+ Wrong: + {props.result.results.wrong} +
+
+
+ +
+
+ Total Questions: + {props.result.results.numberOfQuestions} +
+
+ Solved: + {props.result.results.solved} +
+
+
+
); +}; +exports.default = QuizResultCard; diff --git a/website/src/components/Quiz/resultPage/sidebar.js b/website/src/components/Quiz/resultPage/sidebar.js new file mode 100644 index 0000000..0700b22 --- /dev/null +++ b/website/src/components/Quiz/resultPage/sidebar.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var react_1 = require("react"); +var Link_1 = require("@docusaurus/Link"); +require("./sidebar.css"); +var QuizResultSidebar = function (props) { + var isItemActive = function (id) { + if (typeof window === 'undefined') + return false; + // Remove the leading # from the hash + var currentPageId = window.location.hash.substring(1); + return id === currentPageId; + }; + var capitalizeFirstLetter = function (str) { + return str.substring(0, 1).toUpperCase() + str.substring(1); + }; + return (
+

Quiz Results

+ +
); +}; +exports.default = QuizResultSidebar; diff --git a/website/src/components/Term.js b/website/src/components/Term.js new file mode 100644 index 0000000..f812126 --- /dev/null +++ b/website/src/components/Term.js @@ -0,0 +1,141 @@ +"use strict"; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = Term; +var react_1 = require("react"); +var react_dom_1 = require("react-dom"); +var useDocusaurusContext_1 = require("@docusaurus/useDocusaurusContext"); +var react_markdown_1 = require("react-markdown"); +var remark_gfm_1 = require("remark-gfm"); +// Optional raw HTML support (see notes below): +var rehype_raw_1 = require("rehype-raw"); +var dompurify_1 = require("dompurify"); +function Term(_a) { + var trigger = _a.trigger, tooltipMd = _a.tooltipMd, tooltip = _a.tooltip, tooltipHtml = _a.tooltipHtml, id = _a.id, children = _a.children; + var siteConfig = (0, useDocusaurusContext_1.default)().siteConfig; + var baseUrl = ((siteConfig === null || siteConfig === void 0 ? void 0 : siteConfig.baseUrl) || "/").replace(/\/$/, ""); + var _b = react_1.default.useState(false), open = _b[0], setOpen = _b[1]; + var ref = react_1.default.useRef(null); + var _c = react_1.default.useState({ + top: 0, + left: 0, + width: 0, + }), coords = _c[0], setCoords = _c[1]; + var _d = react_1.default.useState(false), portalReady = _d[0], setPortalReady = _d[1]; + react_1.default.useEffect(function () { + var onDocClick = function (e) { + if (ref.current && !ref.current.contains(e.target)) + setOpen(false); + }; + document.addEventListener("click", onDocClick); + return function () { return document.removeEventListener("click", onDocClick); }; + }, []); + react_1.default.useEffect(function () { + if (typeof window === "undefined") + return; + setPortalReady(true); + }, []); + var updatePosition = react_1.default.useCallback(function () { + if (!ref.current || typeof window === "undefined") + return; + var rect = ref.current.getBoundingClientRect(); + var scrollY = window.scrollY || window.pageYOffset; + var scrollX = window.scrollX || window.pageXOffset; + setCoords({ + top: rect.top + scrollY + rect.height + 4, + left: rect.left + scrollX, + width: rect.width, + }); + }, []); + react_1.default.useEffect(function () { + if (!open) + return; + updatePosition(); + var handler = function () { return updatePosition(); }; + window.addEventListener("scroll", handler, true); + window.addEventListener("resize", handler); + return function () { + window.removeEventListener("scroll", handler, true); + window.removeEventListener("resize", handler); + }; + }, [open, updatePosition]); + var hasTooltip = Boolean(tooltipMd || tooltip || tooltipHtml || children); + // If you expect authors to use "\n" in attribute strings, you can normalize them: + var tooltipMdNormalized = typeof tooltipMd === "string" ? tooltipMd.replaceAll("\\n", "\n") : undefined; + return ( + {/* Trigger text; for inline directives, this is the directive label */} + {trigger !== null && trigger !== void 0 ? trigger : children} + + {open && hasTooltip && portalReady + ? (0, react_dom_1.createPortal)(
+ {tooltipMdNormalized && (; + }, + a: function (_a) { + var _node = _a.node, href = _a.href, props = __rest(_a, ["node", "href"]); + var resolvedHref = href && href.startsWith("/") ? "".concat(baseUrl).concat(href) : href; + return ; + }, + }}> + {tooltipMdNormalized} + )} + + {!tooltipMdNormalized && tooltip && {tooltip}} + + {!tooltipMdNormalized && !tooltip && tooltipHtml && ()} + + {!tooltipMdNormalized && !tooltip && !tooltipHtml && children && <>{children}} +
, document.body) + : null} +
); +} diff --git a/website/src/pages/index.js b/website/src/pages/index.js new file mode 100644 index 0000000..0213267 --- /dev/null +++ b/website/src/pages/index.js @@ -0,0 +1,42 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = Home; +var clsx_1 = require("clsx"); +var Link_1 = require("@docusaurus/Link"); +var useDocusaurusContext_1 = require("@docusaurus/useDocusaurusContext"); +var Layout_1 = require("@theme/Layout"); +var HomepageFeatures_1 = require("@site/src/components/HomepageFeatures"); +var Heading_1 = require("@theme/Heading"); +var index_module_css_1 = require("./index.module.css"); +function HomepageHeader() { + var siteConfig = (0, useDocusaurusContext_1.default)().siteConfig; + return (
+
+ + {siteConfig.title} + +

{siteConfig.tagline}

+
+

+ + Open the Syllabus Online + +

+
+
+ + Download the Syllabus PDF + +
+
+
); +} +function Home() { + var siteConfig = (0, useDocusaurusContext_1.default)().siteConfig; + return ( + +
+ +
+
); +} diff --git a/website/src/theme/Admonition/index.js b/website/src/theme/Admonition/index.js new file mode 100644 index 0000000..eb0395e --- /dev/null +++ b/website/src/theme/Admonition/index.js @@ -0,0 +1,49 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = AdmonitionWrapper; +var react_1 = require("react"); +var Admonition_1 = require("@theme-original/Admonition"); +var RF_svg_1 = require("@site/static/img/RF.svg"); +var K1_svg_1 = require("@site/static/img/K1.svg"); +var K2_svg_1 = require("@site/static/img/K2.svg"); +var K3_svg_1 = require("@site/static/img/K3.svg"); +function AdmonitionWrapper(props) { + if (props.type === 'lo') { + var newProps = __assign(__assign({}, props), { type: 'info' }); + return (<> + } {...newProps}/> + ); + } + if (props.type === 'K1') { + var newProps = __assign(__assign({}, props), { type: 'note' }); + return (<> + } {...newProps}/> + ); + } + if (props.type === 'K2') { + var newProps = __assign(__assign({}, props), { type: 'tip' }); + return (<> + } {...newProps}/> + ); + } + if (props.type === 'K3') { + var newProps = __assign(__assign({}, props), { type: 'warning' }); + return (<> + } {...newProps}/> + ); + } + return (<> + + ); +} diff --git a/website/src/theme/MDXComponents.js b/website/src/theme/MDXComponents.js new file mode 100644 index 0000000..f0be515 --- /dev/null +++ b/website/src/theme/MDXComponents.js @@ -0,0 +1,16 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var MDXComponents_1 = require("@theme-original/MDXComponents"); +var Term_1 = require("@site/src/components/Term"); +exports.default = __assign(__assign({}, MDXComponents_1.default), { Term: Term_1.default }); From 061abff5935f4af1165e558b304cd142360c9b14 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 13:00:45 +0000 Subject: [PATCH 6/6] Remove build artifacts and update .gitignore - Removed accidentally committed TypeScript build artifacts (.js files) - Updated .gitignore to exclude compiled JS files from TS sources - Kept legitimate source .js files (quizPrebuild.js, remark plugins) Co-authored-by: Snooz82 <41592183+Snooz82@users.noreply.github.com> --- website/.gitignore | 10 + website/docusaurus.config.js | 178 --------------- website/sidebars.js | 30 --- .../src/components/Glossary/GlossaryTable.js | 214 ------------------ .../src/components/HomepageFeatures/index.js | 79 ------- website/src/components/Quiz/Quiz.js | 14 -- website/src/components/Quiz/QuizComponent.js | 182 --------------- website/src/components/Quiz/QuizStore.js | 50 ---- website/src/components/Quiz/quizComponents.js | 20 -- .../components/Quiz/resultPage/resultCard.js | 56 ----- .../src/components/Quiz/resultPage/sidebar.js | 39 ---- website/src/components/Term.js | 141 ------------ website/src/pages/index.js | 42 ---- website/src/theme/Admonition/index.js | 49 ---- website/src/theme/MDXComponents.js | 16 -- 15 files changed, 10 insertions(+), 1110 deletions(-) delete mode 100644 website/docusaurus.config.js delete mode 100644 website/sidebars.js delete mode 100644 website/src/components/Glossary/GlossaryTable.js delete mode 100644 website/src/components/HomepageFeatures/index.js delete mode 100644 website/src/components/Quiz/Quiz.js delete mode 100644 website/src/components/Quiz/QuizComponent.js delete mode 100644 website/src/components/Quiz/QuizStore.js delete mode 100644 website/src/components/Quiz/quizComponents.js delete mode 100644 website/src/components/Quiz/resultPage/resultCard.js delete mode 100644 website/src/components/Quiz/resultPage/sidebar.js delete mode 100644 website/src/components/Term.js delete mode 100644 website/src/pages/index.js delete mode 100644 website/src/theme/Admonition/index.js delete mode 100644 website/src/theme/MDXComponents.js diff --git a/website/.gitignore b/website/.gitignore index b2d6de3..4244041 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -8,6 +8,16 @@ .docusaurus .cache-loader +# Build artifacts - TypeScript compiled JS files from TS sources +docusaurus.config.js +sidebars.js +/src/components/**/*.js +/src/pages/**/*.js +/src/theme/**/*.js +# Keep these JS files that are source files, not build artifacts: +!/src/components/Quiz/quizPrebuild.js +!/src/remark/*.js + # Misc .DS_Store .env.local diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js deleted file mode 100644 index 7e2a508..0000000 --- a/website/docusaurus.config.js +++ /dev/null @@ -1,178 +0,0 @@ -"use strict"; -// @ts-check -// Note: type annotations allow type checking and IDEs autocompletion -Object.defineProperty(exports, "__esModule", { value: true }); -var lightCodeTheme = require('prism-react-renderer').themes.vsLight; -var darkCodeTheme = require('prism-react-renderer').themes.dracula; -var remark_directive_1 = require("remark-directive"); -var remark_term_directive_js_1 = require("./src/remark/remark-term-directive.js"); -var remark_code_max_line_length_js_1 = require("./src/remark/remark-code-max-line-length.js"); -/** @type {import('@docusaurus/types').Config} */ -var config = { - title: 'Syllabus of Robot Framework® Certified Professional', - tagline: 'The foundation for the "Robot Framework® Certified Professional" (RFCP®) exam and training', - url: 'https://robotframework.org', - baseUrl: '/robotframework-RFCP-syllabus/', - onBrokenLinks: 'throw', - markdown: { - hooks: { - onBrokenMarkdownLinks: 'throw', - }, - }, - favicon: 'img/rf_favicon.png', - organizationName: 'robotframework', // Usually your GitHub org/user name. - projectName: 'robotframework-RFCP-syllabus', // Usually your repo name. - trailingSlash: false, - presets: [ - [ - 'classic', - /** @type {import('@docusaurus/preset-classic').Options} */ - ({ - docs: { - admonitions: { - keywords: ['lo', 'K1', 'K2', 'K3', 'note', 'tip', 'info', 'warning', 'danger'], - extendDefaults: true, - }, - routeBasePath: '/docs', - sidebarPath: require.resolve('./sidebars.js'), - // Please change this to your repo. - // editUrl: 'https://github.com/robotframework/robotframework-RFCP-syllabus/edit/docusaurus/website', - remarkPlugins: [remark_directive_1.default, remark_term_directive_js_1.default, [remark_code_max_line_length_js_1.default, { max: 100 }]], - }, - blog: false, - theme: { - customCss: require.resolve('./src/css/custom.css'), - }, - }), - ], - ], - themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - ({ - colorMode: { - defaultMode: 'dark', - disableSwitch: false, - respectPrefersColorScheme: false, - }, - navbar: { - title: 'RFCP-Syllabus', - logo: { - alt: 'Robot Framework Logo', - src: 'img/robot-framework.svg', - srcDark: 'img/robot-framework-dark.svg', - }, - items: [ - { - label: 'Introduction', - to: '/docs/overview', - position: 'left', - }, - { - label: 'Chapter 1', - to: '/docs/chapter-01/overview', - position: 'left', - }, - { - label: 'Chapter 2', - to: '/docs/chapter-02/overview', - position: 'left', - }, - { - label: 'Chapter 3', - to: '/docs/chapter-03/overview', - position: 'left', - }, - { - label: 'Chapter 4', - to: '/docs/chapter-04/overview', - position: 'left', - }, - { - label: 'Chapter 5', - to: '/docs/chapter-05/overview', - position: 'left', - }, - { - label: 'Example Exam', - to: '/docs/example-exam', - position: 'left', - }, - { - label: 'LOs', - to: '/docs/learning_objectives', - position: 'left', - }, - // { - // href: 'https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html', - // label: 'User Guide', - // position: 'right', - // }, - // { - // href: 'https://robotframework.org/robotframework/#standard-libraries', - // label: 'Standard Library', - // position: 'right', - // }, - // { - // href: 'https://robot-framework.readthedocs.io/en/stable/', - // label: 'API Documentation', - // position: 'right', - // }, - // { - // href: 'https://slack.robotframework.org/', - // label: 'Slack', - // position: 'right', - // }, - // { - // href: 'https://github.com/robotframework/robotframework-RFCP-syllabus', - // label: 'GitHub', - // position: 'right', - // }, - ], - }, - footer: { - style: 'dark', - links: [ - // { - // title: 'Docs', - // items: [ - // { - // label: 'Syllabus', - // to: '/docs/overview', - // }, - // // { - // // href: 'https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html', - // // label: 'User Guide', - // // }, - // // { - // // href: 'https://robotframework.org/robotframework/#standard-libraries', - // // label: 'Standard Library', - // // }, - // // { - // // href: 'https://robot-framework.readthedocs.io/en/stable/', - // // label: 'API Documentation', - // // }, - // ], - // }, - // { - // title: 'More', - // items: [ - // { - // label: 'GitHub', - // href: 'https://github.com/robotframework/robotframework-RFCP-syllabus', - // }, - // ], - // }, - ], - copyright: "Copyright \u00A9 ".concat(new Date().getFullYear(), " Robot Framework\u00AE Foundation - Syllabus of Robot Framework\u00AE Certified Professional"), - }, - prism: { - theme: lightCodeTheme, - darkTheme: darkCodeTheme, - additionalLanguages: ['robotframework', 'python'], - }, - }), - plugins: [ - require.resolve('docusaurus-lunr-search') - ], -}; -module.exports = config; diff --git a/website/sidebars.js b/website/sidebars.js deleted file mode 100644 index 934c233..0000000 --- a/website/sidebars.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) -/** - * Creating a sidebar enables you to: - - create an ordered group of docs - - render a sidebar for each doc of that group - - provide next/previous navigation - - The sidebars can be generated from the filesystem, or explicitly defined here. - - Create as many sidebars as you want. - */ -var sidebars = { - // By default, Docusaurus generates a sidebar from the docs folder structure - tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], - // But you can create a sidebar manually - /* - tutorialSidebar: [ - 'intro', - 'hello', - { - type: 'category', - label: 'Tutorial', - items: ['tutorial-basics/create-a-document'], - }, - ], - */ -}; -exports.default = sidebars; diff --git a/website/src/components/Glossary/GlossaryTable.js b/website/src/components/Glossary/GlossaryTable.js deleted file mode 100644 index a603424..0000000 --- a/website/src/components/Glossary/GlossaryTable.js +++ /dev/null @@ -1,214 +0,0 @@ -"use strict"; -var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { - if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { - if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || Array.prototype.slice.call(from)); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var react_1 = require("react"); -var fuse_js_1 = require("fuse.js"); -var clsx_1 = require("clsx"); -var marked_1 = require("marked"); -var dompurify_1 = require("dompurify"); -var glossary_json_1 = require("@site/static/glossary/glossary.json"); -var GlossaryTable_module_css_1 = require("./GlossaryTable.module.css"); -var slugify = function (text) { - return text - .toLowerCase() - .replace(/[^a-z0-9]+/g, '-') - .replace(/(^-+|-+$)/g, ''); -}; -var sanitizeMarkdown = function (markdown) { - var html = marked_1.marked.parse(markdown || '', { async: false }); - return typeof window !== 'undefined' ? dompurify_1.default.sanitize(html) : html; -}; -var GlossaryTable = function () { - var _a = (0, react_1.useState)(''), termQuery = _a[0], setTermQuery = _a[1]; - var _b = (0, react_1.useState)(''), textQuery = _b[0], setTextQuery = _b[1]; - var _c = (0, react_1.useState)(''), activeSlug = _c[0], setActiveSlug = _c[1]; - var _d = (0, react_1.useMemo)(function () { - var glossaryItems = glossary_json_1.default; - var termSet = new Set(glossaryItems.map(function (item) { return item.term; })); - var canonicalEntries = glossaryItems.map(function (item) { - var slug = slugify(item.term); - return { - term: item.term, - abbreviation: item.abbreviation, - definition: item.definition, - definitionHtml: sanitizeMarkdown(item.definition), - canonicalTerm: item.term, - isAlias: false, - slug: slug, - targetSlug: slug, - aliases: item.aliases || [], - }; - }); - var aliasEntries = glossaryItems.flatMap(function (item) { - var canonicalSlug = slugify(item.term); - return (item.aliases || []) - .filter(function (alias) { return !termSet.has(alias); }) - .map(function (alias) { return ({ - term: alias, - abbreviation: '', - definition: "See ".concat(item.term), - definitionHtml: '', // Alias entries don't need HTML since they use a link - canonicalTerm: item.term, - isAlias: true, - slug: slugify(alias), - targetSlug: canonicalSlug, - aliases: [], - }); }); - }); - var aliasMap = new Map(); - canonicalEntries.forEach(function (entry) { return aliasMap.set(entry.slug, entry.targetSlug); }); - aliasEntries.forEach(function (entry) { return aliasMap.set(entry.slug, entry.targetSlug); }); - var combined = __spreadArray(__spreadArray([], canonicalEntries, true), aliasEntries, true).sort(function (a, b) { return a.term.localeCompare(b.term); }); - return { entries: combined, aliasToCanonicalSlug: aliasMap }; - }, []), entries = _d.entries, aliasToCanonicalSlug = _d.aliasToCanonicalSlug; - var fuse = (0, react_1.useMemo)(function () { - return new fuse_js_1.default(entries, { - keys: [ - { name: 'term', weight: 0.5 }, - { name: 'definition', weight: 0.4 }, - { name: 'abbreviation', weight: 0.1 }, - { name: 'aliases', weight: 0.3 }, - ], - threshold: 0.35, - ignoreLocation: true, - }); - }, [entries]); - var focusEntry = (0, react_1.useCallback)(function (slug, canonicalTerm) { - if (!slug || typeof window === 'undefined') { - return; - } - var targetSlug = slug; - setActiveSlug(targetSlug); - var url = new URL(window.location.href); - url.hash = targetSlug; - if (canonicalTerm) { - url.searchParams.set('term', canonicalTerm); - } - else { - url.searchParams.set('term', targetSlug); - } - window.history.replaceState({}, '', url.toString()); - var target = document.getElementById(targetSlug); - if (target) { - var top_1 = target.getBoundingClientRect().top + window.scrollY - 70; // account for sticky header - window.scrollTo({ top: top_1, behavior: 'smooth' }); - } - }, []); - (0, react_1.useEffect)(function () { - if (typeof window === 'undefined') { - return; - } - var params = new URLSearchParams(window.location.search); - var termParam = params.get('term'); - var hashParam = window.location.hash ? window.location.hash.replace('#', '') : ''; - var rawSlug = hashParam || (termParam ? slugify(termParam) : ''); - var initialSlug = aliasToCanonicalSlug.get(rawSlug) || rawSlug; - if (initialSlug) { - setActiveSlug(initialSlug); - // Allow the page to render before scrolling - setTimeout(function () { return focusEntry(initialSlug, termParam || initialSlug); }, 50); - } - }, [aliasToCanonicalSlug, focusEntry]); - var filteredEntries = (0, react_1.useMemo)(function () { - var normalize = function (value) { return value.toLowerCase(); }; - var subset = entries; - if (termQuery.trim()) { - var query_1 = normalize(termQuery.trim()); - subset = subset.filter(function (entry) { - return (normalize(entry.term).includes(query_1) || - normalize(entry.canonicalTerm).includes(query_1) || - (entry.aliases || []).some(function (alias) { return normalize(alias).includes(query_1); })); - }); - } - if (textQuery.trim()) { - var results = fuse.search(textQuery.trim()); - var allowedSlugs_1 = new Set(); - results.forEach(function (_a) { - var item = _a.item; - return allowedSlugs_1.add(item.slug); - }); - subset = subset.filter(function (entry) { return allowedSlugs_1.has(entry.slug); }); - } - return subset; - }, [entries, fuse, termQuery, textQuery]); - return (
-
- - -
- -
- - - - - - - - - {filteredEntries.map(function (entry) { - var _a; - var handleClick = function () { return focusEntry(entry.targetSlug, entry.canonicalTerm); }; - return ( - - - ); - })} - -
TermDefinition & Abbreviation
-
{entry.term}
-
- {entry.isAlias ? ( - // Hyperlink to term in alias definition cell - - See {entry.canonicalTerm} - ) : (<> -
-
- {entry.abbreviation ? ( - {entry.abbreviation} - ) : null} - {(entry.aliases || []).map(function (alias) { - var aliasSlug = slugify(alias); - var target = aliasToCanonicalSlug.get(aliasSlug) || aliasSlug; - return ( - // Link to alias term - - {alias} - ); - })} -
- )} -
-
-
); -}; -exports.default = GlossaryTable; diff --git a/website/src/components/HomepageFeatures/index.js b/website/src/components/HomepageFeatures/index.js deleted file mode 100644 index 346715e..0000000 --- a/website/src/components/HomepageFeatures/index.js +++ /dev/null @@ -1,79 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = HomepageFeatures; -var clsx_1 = require("clsx"); -var Heading_1 = require("@theme/Heading"); -var styles_module_css_1 = require("./styles.module.css"); -var Link_1 = require("@docusaurus/Link"); -var FeatureList = [ - { - title: '0. About the Syllabus', - description: (<> - This chapter provides an overview of the Robot Framework® Certified Professional (RFCP®) syllabus, - detailing the course structure, learning objectives, and the foundational knowledge required for certification. - ), - link: '/docs/overview', - }, - { - title: '1. Introduction to Robot Framework', - description: (<> - This chapter introduces Robot Framework, detailing its primary use cases, - its architecture, core components, specification styles, and introduces the Robot Framework Foundation. - ), - link: '/docs/chapter-01/overview', - }, - { - title: '2. Getting Started with Robot Framework', - description: (<> - This chapter introduces the foundational concepts of Robot Framework, - execution processes, the utilization of libraries and resource files, - how to read keyword documentation, and how to write first tests. - ), - link: '/docs/chapter-02/overview', - }, - { - title: '3. Keyword Design, Variables, and Resource Files', - description: (<> - This chapter delves into the essential components of - Robot Framework, such as **Variables**, **User Keywords**, **Resource Files**, - and Data-Driven Testing. - ), - link: '/docs/chapter-03/overview', - }, - { - title: '4. Advanced Structuring and Execution', - description: (<> - This chapter delves into advanced techniques for structuring - and executing Robot Framework, explaining the use of - **Setups** and **Teardowns**, and the application of tags - to efficiently filter and control execution. - ), - link: '/docs/chapter-04/overview', - }, - { - title: '5. Exploring Advanced Constructs', - description: (<> - This chapter introduces advanced constructs in Robot Framework, - such as advanced variable handling and control structures like IF and FOR statements. - ), - link: '/docs/chapter-05/overview', - } -]; -function Feature(_a) { - var title = _a.title, description = _a.description, link = _a.link; - return ( -
- {title} -

{description}

-
-
); -} -function HomepageFeatures() { - return (
-
-
- {FeatureList.map(function (props, idx) { return (); })} -
-
-
); -} diff --git a/website/src/components/Quiz/Quiz.js b/website/src/components/Quiz/Quiz.js deleted file mode 100644 index f6ef29c..0000000 --- a/website/src/components/Quiz/Quiz.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = QuizLoader; -var react_1 = require("react"); -var ExecutionEnvironment_1 = require("@docusaurus/ExecutionEnvironment"); -var QuizComponent = react_1.default.lazy(function () { return Promise.resolve().then(function () { return require('./QuizComponent'); }); }); -function QuizLoader(_a) { - var name = _a.name, question = _a.question, src = _a.src; - if (!ExecutionEnvironment_1.default.canUseDOM) - return null; - return (Loading Quiz...
}> - - ); -} diff --git a/website/src/components/Quiz/QuizComponent.js b/website/src/components/Quiz/QuizComponent.js deleted file mode 100644 index e9384ad..0000000 --- a/website/src/components/Quiz/QuizComponent.js +++ /dev/null @@ -1,182 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); - return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Quiz; -var react_1 = require("react"); -var ExecutionEnvironment_1 = require("@docusaurus/ExecutionEnvironment"); -var github_light_1 = require("@shikijs/themes/github-light"); -var dracula_1 = require("@shikijs/themes/dracula"); -var quizdown_es_js_1 = require("quizdown-extended/dist/quizdown.es.js"); -var QuizStore_1 = require("./QuizStore"); -require("./Quiz.css"); -var python_1 = require("@shikijs/langs/python"); -var robotframework_tmLanguage_json_1 = require("./robotframework-tmLanguage.json"); -function Quiz(_a) { - var _this = this; - var name = _a.name, question = _a.question, src = _a.src; - var addQuizResult = (0, QuizStore_1.default)(function (state) { return state.addQuizResult; }); - // const resultBaseUrl = useBaseUrl('/quizResults'); - var _b = (0, react_1.useState)(question || null), content = _b[0], setContent = _b[1]; - var generateQuizId = function (name) { - var page = typeof window !== 'undefined' ? window.location.pathname : ''; - page = page.replace('/robotframework-RFCP-syllabus/', ''); - var id = page.replace('docs/', '').replace('/', '_').replace('-', '_') + '_' + name.replace(' ', '_'); - return id.toLocaleLowerCase(); - }; - var genQuizId = function () { - if (ExecutionEnvironment_1.default.canUseDOM) { - return generateQuizId(name); - } - return 'quiz-id'; - }; - // const generateResultLink = () => { - // if (ExecutionEnvironment.canUseDOM) { - // return resultBaseUrl + '#' + generateQuizId(name); - // } - // return '#'; - // }; - // Load quiz content from external file if src is provided - (0, react_1.useEffect)(function () { - if (!src) - return; - fetch('/robotframework-RFCP-syllabus/quizzes/' + src) - .then(function (res) { - if (!res.ok) - throw new Error("Failed to fetch quiz: ".concat(res.status)); - return res.text(); - }) - .then(function (text) { - setContent(text); - }) - .catch(function (err) { - console.error('Error loading quiz:', err); - }); - }, [src, name]); - (0, react_1.useEffect)(function () { - if (!ExecutionEnvironment_1.default.canUseDOM || !content) { - return; - } - // Set CSS variables for component colors (existing) - document.documentElement.style.setProperty('--quizdownPrimaryColor', 'var(--quizdown-color-primary)'); - document.documentElement.style.setProperty('--quizdownSecondaryColor', 'var(--quizdown-color-secondary)'); - document.documentElement.style.setProperty('--quizdownTextColor', 'var(--quizdown-color-text)'); - document.documentElement.style.setProperty('--quizdownButtonColor', 'var(--quizdown-color-button)'); - document.documentElement.style.setProperty('--quizdownColorShadow', 'var(--quizdown-color-shadow)'); - document.documentElement.style.setProperty('--quizdownBackgroundColor', 'var(--quizdown-color-background, var(--ifm-navbar-background-color))'); - document.documentElement.style.setProperty('--quizdownColorHint', 'var(--quizdown-color-hint)'); - document.documentElement.style.setProperty('--quizdownColorHintBg', 'var(--quizdown-color-hint-bg)'); - document.documentElement.style.setProperty('--quizdownColorPass', 'var(--quizdown-color-pass)'); - document.documentElement.style.setProperty('--quizdownColorPassBg', 'var(--quizdown-color-pass-bg)'); - document.documentElement.style.setProperty('--quizdownColorFail', 'var(--quizdown-color-fail)'); - document.documentElement.style.setProperty('--quizdownColorFailBg', 'var(--quizdown-color-fail-bg)'); - document.documentElement.style.setProperty('--quizdownColorCodeBg', 'var(--quizdown-color-code-bg)'); - var node = document.querySelector('#' + genQuizId()); - if (!node) { - console.error("[Quiz:".concat(name, "] Could not find #").concat(genQuizId())); - return; - } - var quizdown = new quizdown_es_js_1.default(); - // this.hintSymbolColor = get(options['hintSymbolColor'], '#ff9800'); - // this.hintBgColor = get(options['hintBgColor'], '#ff990040'); - // this.passSymbolColor = get(options['passSymbolColor'], '#00cc88'); - // this.passBgColor = get(options['passBgColor'], '#00cc8840'); - // this.failSymbolColor = get(options['failSymbolColor'], '#e72323'); - // this.failBgColor = get(options['failBgColor'], '#e7232340'); - // this.infoSymbolColor = get(options['infoSymbolColor'], '#2196F3'); - // this.submitSymbolColor = get(options['submitSymbolColor'], '#2196F3'); - // - var config = { - startOnLoad: true, - shuffleAnswers: true, - shuffleQuestions: true, - nQuestions: undefined, - primaryColor: 'var(--quizdownPrimaryColor)', - secondaryColor: 'var(--quizdownSecondaryColor)', - textColor: 'var(--quizdownTextColor)', - buttonColor: 'var(--quizdownButtonColor)', - shadowColor: 'var(--quizdownColorShadow)', - backgroundColor: 'var(--quizdownBackgroundColor)', - hintSymbolColor: 'var(--quizdownColorHint)', - hintBgColor: 'var(--quizdownColorHintBg)', - passSymbolColor: 'var(--quizdownColorPass)', - passBgColor: 'var(--quizdownColorPassBg)', - failSymbolColor: 'var(--quizdownColorFail)', - failBgColor: 'var(--quizdownColorFailBg)', - codeBgColor: 'var(--quizdownColorCodeBg)', - locale: 'en', - enableRetry: true, - // NEW: Font configuration (requires updated quizdown files) - fontFamilyHeading: 'Roboto, sans-serif', - //'var(--ifm-font-family-heading)', - // NEW: Custom styles to match Docusaurus - customStyles: "\n .quizdown-content {\n font-size: var(--ifm-font-size-base, 16px);\n line-height: var(--ifm-line-height-base, 1.65);\n }\n " - }; - quizdown.createApp(content, node, config); - // quizdown.hooks.onQuizFinish((event) => { - // addQuizResult( - // generateQuizId(name), - // event.numberOfQuestions, - // event.solved, - // event.right, - // event.wrong - // ); - // }); - quizdown.getShikiInstance().then(function (instance) { return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, quizdown.registerShikiLanguage(python_1.default)]; - case 1: - _a.sent(); - return [4 /*yield*/, quizdown.registerShikiLanguage(robotframework_tmLanguage_json_1.default)]; - case 2: - _a.sent(); - return [4 /*yield*/, quizdown.registerShikiTheme('light', 'light', github_light_1.default)]; - case 3: - _a.sent(); - return [4 /*yield*/, quizdown.registerShikiTheme('dark', 'dark', dracula_1.default)]; - case 4: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - }, [content, name]); - return ( - - ); -} diff --git a/website/src/components/Quiz/QuizStore.js b/website/src/components/Quiz/QuizStore.js deleted file mode 100644 index e1b100d..0000000 --- a/website/src/components/Quiz/QuizStore.js +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; -var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { - if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { - if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || Array.prototype.slice.call(from)); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var zustand_1 = require("zustand"); -var middleware_1 = require("zustand/middleware"); -// Create the store -var useQuizStore = (0, zustand_1.create)()((0, middleware_1.persist)(function (set, get) { return ({ - quiz: [], - // Action to add a new quiz - addQuizResult: function (quizId, numberOfQuestions, solved, right, wrong) { - var state = get(); - var id = self.crypto.randomUUID(); - ; - var timestamp = new Date().toISOString(); - // Otherwise add the new quiz - set({ - quiz: __spreadArray(__spreadArray([], state.quiz, true), [ - { - id: id, - quizId: quizId, - timestamp: timestamp, - results: { - numberOfQuestions: numberOfQuestions, - solved: solved, - right: right, - wrong: wrong, - } - } - ], false) - }); - return id; - }, - getQuizResults: function (quizId) { - var state = get(); - return state.quiz.filter(function (value) { - return value.quizId === quizId; - }); - } -}); }, { - name: 'quiz-results', // unique name for localStorage -})); -exports.default = useQuizStore; diff --git a/website/src/components/Quiz/quizComponents.js b/website/src/components/Quiz/quizComponents.js deleted file mode 100644 index a6e087a..0000000 --- a/website/src/components/Quiz/quizComponents.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; -/* -* This file is automatically generated and will be overridden when running the build process. -* Generated on: 12/5/2025, 1:04:36 PM -*/ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.quizPages = void 0; -exports.quizPages = [ - { - "id": "docs-example-exam", - "name": "example-exam", - "quizzes": [ - { - "id": "example-exam#example", - "name": "Example", - "src": "Example.md" - } - ] - } -]; diff --git a/website/src/components/Quiz/resultPage/resultCard.js b/website/src/components/Quiz/resultPage/resultCard.js deleted file mode 100644 index 2835790..0000000 --- a/website/src/components/Quiz/resultPage/resultCard.js +++ /dev/null @@ -1,56 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var react_1 = require("react"); -require("./resultCard.css"); -var QuizResultCard = function (props) { - // Calculate success rate - var successRate = Math.round((props.result.results.right / props.result.results.numberOfQuestions) * 100); - // Format timestamp to a more readable format - var formatTimestamp = function (timestamp) { - try { - var date = new Date(timestamp); - return date.toLocaleString(); - } - catch (e) { - return timestamp; - } - }; - return (
-
-

{formatTimestamp(props.result.timestamp)}

- -
- -
-
-
- {successRate}% -
-
-
- Right: - {props.result.results.right} -
-
- Wrong: - {props.result.results.wrong} -
-
-
- -
-
- Total Questions: - {props.result.results.numberOfQuestions} -
-
- Solved: - {props.result.results.solved} -
-
-
-
); -}; -exports.default = QuizResultCard; diff --git a/website/src/components/Quiz/resultPage/sidebar.js b/website/src/components/Quiz/resultPage/sidebar.js deleted file mode 100644 index 0700b22..0000000 --- a/website/src/components/Quiz/resultPage/sidebar.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var react_1 = require("react"); -var Link_1 = require("@docusaurus/Link"); -require("./sidebar.css"); -var QuizResultSidebar = function (props) { - var isItemActive = function (id) { - if (typeof window === 'undefined') - return false; - // Remove the leading # from the hash - var currentPageId = window.location.hash.substring(1); - return id === currentPageId; - }; - var capitalizeFirstLetter = function (str) { - return str.substring(0, 1).toUpperCase() + str.substring(1); - }; - return (
-

Quiz Results

- -
); -}; -exports.default = QuizResultSidebar; diff --git a/website/src/components/Term.js b/website/src/components/Term.js deleted file mode 100644 index f812126..0000000 --- a/website/src/components/Term.js +++ /dev/null @@ -1,141 +0,0 @@ -"use strict"; -var __rest = (this && this.__rest) || function (s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Term; -var react_1 = require("react"); -var react_dom_1 = require("react-dom"); -var useDocusaurusContext_1 = require("@docusaurus/useDocusaurusContext"); -var react_markdown_1 = require("react-markdown"); -var remark_gfm_1 = require("remark-gfm"); -// Optional raw HTML support (see notes below): -var rehype_raw_1 = require("rehype-raw"); -var dompurify_1 = require("dompurify"); -function Term(_a) { - var trigger = _a.trigger, tooltipMd = _a.tooltipMd, tooltip = _a.tooltip, tooltipHtml = _a.tooltipHtml, id = _a.id, children = _a.children; - var siteConfig = (0, useDocusaurusContext_1.default)().siteConfig; - var baseUrl = ((siteConfig === null || siteConfig === void 0 ? void 0 : siteConfig.baseUrl) || "/").replace(/\/$/, ""); - var _b = react_1.default.useState(false), open = _b[0], setOpen = _b[1]; - var ref = react_1.default.useRef(null); - var _c = react_1.default.useState({ - top: 0, - left: 0, - width: 0, - }), coords = _c[0], setCoords = _c[1]; - var _d = react_1.default.useState(false), portalReady = _d[0], setPortalReady = _d[1]; - react_1.default.useEffect(function () { - var onDocClick = function (e) { - if (ref.current && !ref.current.contains(e.target)) - setOpen(false); - }; - document.addEventListener("click", onDocClick); - return function () { return document.removeEventListener("click", onDocClick); }; - }, []); - react_1.default.useEffect(function () { - if (typeof window === "undefined") - return; - setPortalReady(true); - }, []); - var updatePosition = react_1.default.useCallback(function () { - if (!ref.current || typeof window === "undefined") - return; - var rect = ref.current.getBoundingClientRect(); - var scrollY = window.scrollY || window.pageYOffset; - var scrollX = window.scrollX || window.pageXOffset; - setCoords({ - top: rect.top + scrollY + rect.height + 4, - left: rect.left + scrollX, - width: rect.width, - }); - }, []); - react_1.default.useEffect(function () { - if (!open) - return; - updatePosition(); - var handler = function () { return updatePosition(); }; - window.addEventListener("scroll", handler, true); - window.addEventListener("resize", handler); - return function () { - window.removeEventListener("scroll", handler, true); - window.removeEventListener("resize", handler); - }; - }, [open, updatePosition]); - var hasTooltip = Boolean(tooltipMd || tooltip || tooltipHtml || children); - // If you expect authors to use "\n" in attribute strings, you can normalize them: - var tooltipMdNormalized = typeof tooltipMd === "string" ? tooltipMd.replaceAll("\\n", "\n") : undefined; - return ( - {/* Trigger text; for inline directives, this is the directive label */} - {trigger !== null && trigger !== void 0 ? trigger : children} - - {open && hasTooltip && portalReady - ? (0, react_dom_1.createPortal)(
- {tooltipMdNormalized && (; - }, - a: function (_a) { - var _node = _a.node, href = _a.href, props = __rest(_a, ["node", "href"]); - var resolvedHref = href && href.startsWith("/") ? "".concat(baseUrl).concat(href) : href; - return ; - }, - }}> - {tooltipMdNormalized} - )} - - {!tooltipMdNormalized && tooltip && {tooltip}} - - {!tooltipMdNormalized && !tooltip && tooltipHtml && ()} - - {!tooltipMdNormalized && !tooltip && !tooltipHtml && children && <>{children}} -
, document.body) - : null} - ); -} diff --git a/website/src/pages/index.js b/website/src/pages/index.js deleted file mode 100644 index 0213267..0000000 --- a/website/src/pages/index.js +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Home; -var clsx_1 = require("clsx"); -var Link_1 = require("@docusaurus/Link"); -var useDocusaurusContext_1 = require("@docusaurus/useDocusaurusContext"); -var Layout_1 = require("@theme/Layout"); -var HomepageFeatures_1 = require("@site/src/components/HomepageFeatures"); -var Heading_1 = require("@theme/Heading"); -var index_module_css_1 = require("./index.module.css"); -function HomepageHeader() { - var siteConfig = (0, useDocusaurusContext_1.default)().siteConfig; - return (
-
- - {siteConfig.title} - -

{siteConfig.tagline}

-
-

- - Open the Syllabus Online - -

-
-
- - Download the Syllabus PDF - -
-
-
); -} -function Home() { - var siteConfig = (0, useDocusaurusContext_1.default)().siteConfig; - return ( - -
- -
-
); -} diff --git a/website/src/theme/Admonition/index.js b/website/src/theme/Admonition/index.js deleted file mode 100644 index eb0395e..0000000 --- a/website/src/theme/Admonition/index.js +++ /dev/null @@ -1,49 +0,0 @@ -"use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = AdmonitionWrapper; -var react_1 = require("react"); -var Admonition_1 = require("@theme-original/Admonition"); -var RF_svg_1 = require("@site/static/img/RF.svg"); -var K1_svg_1 = require("@site/static/img/K1.svg"); -var K2_svg_1 = require("@site/static/img/K2.svg"); -var K3_svg_1 = require("@site/static/img/K3.svg"); -function AdmonitionWrapper(props) { - if (props.type === 'lo') { - var newProps = __assign(__assign({}, props), { type: 'info' }); - return (<> - } {...newProps}/> - ); - } - if (props.type === 'K1') { - var newProps = __assign(__assign({}, props), { type: 'note' }); - return (<> - } {...newProps}/> - ); - } - if (props.type === 'K2') { - var newProps = __assign(__assign({}, props), { type: 'tip' }); - return (<> - } {...newProps}/> - ); - } - if (props.type === 'K3') { - var newProps = __assign(__assign({}, props), { type: 'warning' }); - return (<> - } {...newProps}/> - ); - } - return (<> - - ); -} diff --git a/website/src/theme/MDXComponents.js b/website/src/theme/MDXComponents.js deleted file mode 100644 index f0be515..0000000 --- a/website/src/theme/MDXComponents.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var MDXComponents_1 = require("@theme-original/MDXComponents"); -var Term_1 = require("@site/src/components/Term"); -exports.default = __assign(__assign({}, MDXComponents_1.default), { Term: Term_1.default });