@fundamental-styles/mcp 0.41.6 → 0.41.7-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/CHANGELOG.md +7 -3
- package/data/component-guidance.json +2625 -0
- package/data/component-use-cases.json +51 -8
- package/package.json +1 -1
- package/src/data/load-catalog.d.ts +18 -1
- package/src/data/load-catalog.js +7 -1
- package/src/data/load-catalog.js.map +1 -1
- package/src/server.js +538 -8
- package/src/server.js.map +1 -1
- package/src/types/component-metadata.d.ts +17 -0
- package/src/types/component-metadata.js.map +1 -1
package/src/server.js
CHANGED
|
@@ -25,7 +25,9 @@ catch (_a) {
|
|
|
25
25
|
accessibility: null,
|
|
26
26
|
utilityClasses: null,
|
|
27
27
|
designTokens: [],
|
|
28
|
-
htmlExamples: null
|
|
28
|
+
htmlExamples: null,
|
|
29
|
+
componentUseCases: null,
|
|
30
|
+
componentGuidance: null
|
|
29
31
|
};
|
|
30
32
|
console.error('Warning: Failed to load component catalog data.');
|
|
31
33
|
}
|
|
@@ -74,13 +76,19 @@ Use this to discover what CSS components are available.`, {
|
|
|
74
76
|
((_b = c.subcategory) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(lowerCategory));
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
|
-
const summary = components.map((c) =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
const summary = components.map((c) => {
|
|
80
|
+
var _a;
|
|
81
|
+
// Try to get enhanced description from component guidance
|
|
82
|
+
const guidance = (_a = data.componentGuidance) === null || _a === void 0 ? void 0 : _a.components[c.id];
|
|
83
|
+
const description = (guidance === null || guidance === void 0 ? void 0 : guidance.description) || c.description;
|
|
84
|
+
return {
|
|
85
|
+
id: c.id,
|
|
86
|
+
name: c.name,
|
|
87
|
+
baseClass: c.baseClass,
|
|
88
|
+
category: (guidance === null || guidance === void 0 ? void 0 : guidance.category) || c.category,
|
|
89
|
+
description: (0, helpers_1.truncate)(description, 120)
|
|
90
|
+
};
|
|
91
|
+
});
|
|
84
92
|
return {
|
|
85
93
|
content: [
|
|
86
94
|
{
|
|
@@ -532,6 +540,82 @@ Use this when building complex layouts to understand component composition.`, {
|
|
|
532
540
|
};
|
|
533
541
|
}));
|
|
534
542
|
// ---------------------------------------------------------------------------
|
|
543
|
+
// Tool: get_component_guidance
|
|
544
|
+
// ---------------------------------------------------------------------------
|
|
545
|
+
server.tool('get_component_guidance', `Get Fiori Design Guidelines for a component including when to use it, when to avoid it, and best practices.
|
|
546
|
+
Returns detailed guidance from SAP Fiori Design System including use cases, anti-patterns, and design tips.
|
|
547
|
+
Use this when you need to understand if a component is appropriate for a specific use case or need design guidance.`, {
|
|
548
|
+
component: zod_1.z.string().describe('Component name or id (e.g., "avatar", "button", "table")')
|
|
549
|
+
}, (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ component }) {
|
|
550
|
+
const comp = findComponent(component);
|
|
551
|
+
if (!comp) {
|
|
552
|
+
return {
|
|
553
|
+
content: [
|
|
554
|
+
{
|
|
555
|
+
type: 'text',
|
|
556
|
+
text: `Component "${component}" not found. Use search_components to find available components.`
|
|
557
|
+
}
|
|
558
|
+
]
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
// Check if component guidance data is available
|
|
562
|
+
if (!data.componentGuidance) {
|
|
563
|
+
return {
|
|
564
|
+
content: [
|
|
565
|
+
{
|
|
566
|
+
type: 'text',
|
|
567
|
+
text: JSON.stringify({ component: comp.name, error: 'Component guidance data not available.' }, null, 2)
|
|
568
|
+
}
|
|
569
|
+
]
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
// Get guidance from the new comprehensive guidance file
|
|
573
|
+
const guidance = data.componentGuidance.components[comp.id];
|
|
574
|
+
if (!guidance) {
|
|
575
|
+
return {
|
|
576
|
+
content: [
|
|
577
|
+
{
|
|
578
|
+
type: 'text',
|
|
579
|
+
text: JSON.stringify({
|
|
580
|
+
component: comp.name,
|
|
581
|
+
baseClass: comp.baseClass,
|
|
582
|
+
note: 'No specific Fiori design guidance available for this component yet.',
|
|
583
|
+
suggestion: 'Check the component catalog or Fiori Design Guidelines website.'
|
|
584
|
+
}, null, 2)
|
|
585
|
+
}
|
|
586
|
+
]
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const result = {
|
|
590
|
+
component: comp.name,
|
|
591
|
+
baseClass: comp.baseClass,
|
|
592
|
+
category: guidance.category
|
|
593
|
+
};
|
|
594
|
+
if (guidance.description) {
|
|
595
|
+
result['description'] = guidance.description;
|
|
596
|
+
}
|
|
597
|
+
if (guidance.whenToUse && guidance.whenToUse.length > 0) {
|
|
598
|
+
result['whenToUse'] = guidance.whenToUse;
|
|
599
|
+
}
|
|
600
|
+
if (guidance.whenToAvoid && guidance.whenToAvoid.length > 0) {
|
|
601
|
+
result['whenToAvoid'] = guidance.whenToAvoid;
|
|
602
|
+
}
|
|
603
|
+
if (guidance.bestPractices && guidance.bestPractices.length > 0) {
|
|
604
|
+
result['bestPractices'] = guidance.bestPractices;
|
|
605
|
+
}
|
|
606
|
+
if (guidance.relatedComponents && guidance.relatedComponents.length > 0) {
|
|
607
|
+
result['relatedComponents'] = guidance.relatedComponents;
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
content: [
|
|
611
|
+
{
|
|
612
|
+
type: 'text',
|
|
613
|
+
text: JSON.stringify(result, null, 2)
|
|
614
|
+
}
|
|
615
|
+
]
|
|
616
|
+
};
|
|
617
|
+
}));
|
|
618
|
+
// ---------------------------------------------------------------------------
|
|
535
619
|
// Tool: get_theme_info
|
|
536
620
|
// ---------------------------------------------------------------------------
|
|
537
621
|
server.tool('get_theme_info', `List available SAP design themes for fundamental-styles and their descriptions.
|
|
@@ -675,6 +759,452 @@ or checking what changed between releases.`, {
|
|
|
675
759
|
]
|
|
676
760
|
};
|
|
677
761
|
}));
|
|
762
|
+
// ---------------------------------------------------------------------------
|
|
763
|
+
// Tool: setup_project
|
|
764
|
+
// ---------------------------------------------------------------------------
|
|
765
|
+
server.tool('setup_project', `Get comprehensive setup instructions for fundamental-styles in a new project.
|
|
766
|
+
Returns detailed step-by-step instructions for both CDN and NPM installation approaches,
|
|
767
|
+
including theme setup, font configuration, component imports, and best practices.
|
|
768
|
+
Use this when starting a new project or helping users get started with fundamental-styles.`, {
|
|
769
|
+
approach: zod_1.z
|
|
770
|
+
.enum(['cdn', 'npm', 'both'])
|
|
771
|
+
.default('both')
|
|
772
|
+
.describe('Installation approach: "cdn" for CDN-only, "npm" for NPM-only, "both" for both approaches'),
|
|
773
|
+
themes: zod_1.z
|
|
774
|
+
.union([
|
|
775
|
+
zod_1.z.enum([
|
|
776
|
+
'sap_horizon',
|
|
777
|
+
'sap_horizon_dark',
|
|
778
|
+
'sap_horizon_hcb',
|
|
779
|
+
'sap_horizon_hcw',
|
|
780
|
+
'sap_fiori_3',
|
|
781
|
+
'sap_fiori_3_dark',
|
|
782
|
+
'sap_fiori_3_hcb',
|
|
783
|
+
'sap_fiori_3_hcw',
|
|
784
|
+
'all',
|
|
785
|
+
'all_horizon',
|
|
786
|
+
'all_fiori',
|
|
787
|
+
'all_dark',
|
|
788
|
+
'all_light',
|
|
789
|
+
'all_high_contrast'
|
|
790
|
+
]),
|
|
791
|
+
zod_1.z.array(zod_1.z.enum([
|
|
792
|
+
'sap_horizon',
|
|
793
|
+
'sap_horizon_dark',
|
|
794
|
+
'sap_horizon_hcb',
|
|
795
|
+
'sap_horizon_hcw',
|
|
796
|
+
'sap_fiori_3',
|
|
797
|
+
'sap_fiori_3_dark',
|
|
798
|
+
'sap_fiori_3_hcb',
|
|
799
|
+
'sap_fiori_3_hcw'
|
|
800
|
+
]))
|
|
801
|
+
])
|
|
802
|
+
.optional()
|
|
803
|
+
.describe('Theme(s) to include. Can be: single theme name, array of theme names, or preset ("all", "all_horizon", "all_fiori", "all_dark", "all_light", "all_high_contrast"). If not provided, defaults to "sap_horizon"'),
|
|
804
|
+
componentMode: zod_1.z
|
|
805
|
+
.enum(['all', 'selective'])
|
|
806
|
+
.default('selective')
|
|
807
|
+
.describe('Import all components or selective components (default: selective)'),
|
|
808
|
+
components: zod_1.z
|
|
809
|
+
.array(zod_1.z.string())
|
|
810
|
+
.optional()
|
|
811
|
+
.describe('Specific components to include (e.g., ["button", "input", "table"]). Only used with componentMode="selective"')
|
|
812
|
+
}, (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ approach, themes, componentMode, components }) {
|
|
813
|
+
const componentList = components || ['button', 'input', 'form-item', 'form-label'];
|
|
814
|
+
// All available themes
|
|
815
|
+
const allThemes = [
|
|
816
|
+
'sap_horizon',
|
|
817
|
+
'sap_horizon_dark',
|
|
818
|
+
'sap_horizon_hcb',
|
|
819
|
+
'sap_horizon_hcw',
|
|
820
|
+
'sap_fiori_3',
|
|
821
|
+
'sap_fiori_3_dark',
|
|
822
|
+
'sap_fiori_3_hcb',
|
|
823
|
+
'sap_fiori_3_hcw'
|
|
824
|
+
];
|
|
825
|
+
// Theme presets
|
|
826
|
+
const horizonThemes = ['sap_horizon', 'sap_horizon_dark', 'sap_horizon_hcb', 'sap_horizon_hcw'];
|
|
827
|
+
const fioriThemes = ['sap_fiori_3', 'sap_fiori_3_dark', 'sap_fiori_3_hcb', 'sap_fiori_3_hcw'];
|
|
828
|
+
const darkThemes = ['sap_horizon_dark', 'sap_fiori_3_dark'];
|
|
829
|
+
const lightThemes = ['sap_horizon', 'sap_fiori_3'];
|
|
830
|
+
const highContrastThemes = ['sap_horizon_hcb', 'sap_horizon_hcw', 'sap_fiori_3_hcb', 'sap_fiori_3_hcw'];
|
|
831
|
+
// Determine which themes to include
|
|
832
|
+
let selectedThemes;
|
|
833
|
+
if (!themes) {
|
|
834
|
+
// Default: single sap_horizon theme
|
|
835
|
+
selectedThemes = ['sap_horizon'];
|
|
836
|
+
}
|
|
837
|
+
else if (Array.isArray(themes)) {
|
|
838
|
+
// Array of specific themes
|
|
839
|
+
if (themes.includes('all')) {
|
|
840
|
+
selectedThemes = allThemes;
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
selectedThemes = themes;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
// Single value (preset or theme name)
|
|
848
|
+
const preset = themes;
|
|
849
|
+
switch (preset) {
|
|
850
|
+
case 'all':
|
|
851
|
+
selectedThemes = allThemes;
|
|
852
|
+
break;
|
|
853
|
+
case 'all_horizon':
|
|
854
|
+
selectedThemes = horizonThemes;
|
|
855
|
+
break;
|
|
856
|
+
case 'all_fiori':
|
|
857
|
+
selectedThemes = fioriThemes;
|
|
858
|
+
break;
|
|
859
|
+
case 'all_dark':
|
|
860
|
+
selectedThemes = darkThemes;
|
|
861
|
+
break;
|
|
862
|
+
case 'all_light':
|
|
863
|
+
selectedThemes = lightThemes;
|
|
864
|
+
break;
|
|
865
|
+
case 'all_high_contrast':
|
|
866
|
+
selectedThemes = highContrastThemes;
|
|
867
|
+
break;
|
|
868
|
+
default:
|
|
869
|
+
// Single theme name
|
|
870
|
+
selectedThemes = [preset];
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
// Build theme-specific instructions for each selected theme
|
|
874
|
+
const themeInstructions = selectedThemes.map(theme => {
|
|
875
|
+
const themeBaseUrl = `https://unpkg.com/@sap-theming/theming-base-content/content/Base/baseLib/${theme}/css_variables.css`;
|
|
876
|
+
const themeFundUrl = `https://unpkg.com/fundamental-styles@latest/dist/theming/${theme}.css`;
|
|
877
|
+
const themeNpmBase = `@sap-theming/theming-base-content/content/Base/baseLib/${theme}/css_variables.css`;
|
|
878
|
+
const themeNpmFund = `fundamental-styles/dist/theming/${theme}.css`;
|
|
879
|
+
return {
|
|
880
|
+
theme,
|
|
881
|
+
cdn: {
|
|
882
|
+
themeBaseUrl,
|
|
883
|
+
themeFundUrl
|
|
884
|
+
},
|
|
885
|
+
npm: {
|
|
886
|
+
themeNpmBase,
|
|
887
|
+
themeNpmFund
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
});
|
|
891
|
+
// Use the first theme for the main example
|
|
892
|
+
const primaryTheme = themeInstructions[0];
|
|
893
|
+
const result = {
|
|
894
|
+
library: 'fundamental-styles',
|
|
895
|
+
version: data.version,
|
|
896
|
+
themes: selectedThemes,
|
|
897
|
+
primaryTheme: primaryTheme.theme,
|
|
898
|
+
approach: approach
|
|
899
|
+
};
|
|
900
|
+
// CDN Instructions
|
|
901
|
+
if (approach === 'cdn' || approach === 'both') {
|
|
902
|
+
const cdnComponentLinks = componentMode === 'all'
|
|
903
|
+
? ['<link href="https://unpkg.com/fundamental-styles@latest/dist/fundamental-styles.css" rel="stylesheet">']
|
|
904
|
+
: componentList.map(c => `<link href="https://unpkg.com/fundamental-styles@latest/dist/${c}.css" rel="stylesheet">`);
|
|
905
|
+
result.cdn = {
|
|
906
|
+
description: 'CDN installation requires no build tools. Perfect for prototyping or static HTML projects.',
|
|
907
|
+
primaryTheme: primaryTheme.theme,
|
|
908
|
+
themes: themeInstructions.map(t => ({
|
|
909
|
+
theme: t.theme,
|
|
910
|
+
themeBaseUrl: t.cdn.themeBaseUrl,
|
|
911
|
+
themeFundUrl: t.cdn.themeFundUrl
|
|
912
|
+
})),
|
|
913
|
+
steps: [
|
|
914
|
+
{
|
|
915
|
+
step: 1,
|
|
916
|
+
title: 'Add Theme CSS to <head>',
|
|
917
|
+
description: selectedThemes.length > 1
|
|
918
|
+
? `Two CSS files are REQUIRED for themes to work. Order matters. Showing setup for ${primaryTheme.theme} (primary theme). See 'themes' array for ${selectedThemes.length - 1} additional theme${selectedThemes.length > 2 ? 's' : ''}.`
|
|
919
|
+
: 'Two CSS files are REQUIRED for themes to work. Order matters.',
|
|
920
|
+
code: `<!-- 1. Theme base variables (required) -->
|
|
921
|
+
<link href="${primaryTheme.cdn.themeBaseUrl}" rel="stylesheet">
|
|
922
|
+
|
|
923
|
+
<!-- 2. Fundamental Styles theme customizations (required) -->
|
|
924
|
+
<link href="${primaryTheme.cdn.themeFundUrl}" rel="stylesheet">`,
|
|
925
|
+
language: 'html'
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
step: 2,
|
|
929
|
+
title: 'Add Component CSS',
|
|
930
|
+
description: componentMode === 'all'
|
|
931
|
+
? 'Import all components in one file (larger bundle size)'
|
|
932
|
+
: 'Import only the components you need (smaller bundle size)',
|
|
933
|
+
code: cdnComponentLinks.join('\n'),
|
|
934
|
+
language: 'html'
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
step: 3,
|
|
938
|
+
title: 'Set Base Font Size',
|
|
939
|
+
description: 'Required for proper component sizing per SAP Design specifications',
|
|
940
|
+
code: `<style>
|
|
941
|
+
html {
|
|
942
|
+
font-size: 16px; /* Required for proper component sizing */
|
|
943
|
+
}
|
|
944
|
+
</style>`,
|
|
945
|
+
language: 'html'
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
step: 4,
|
|
949
|
+
title: 'Use Components in HTML',
|
|
950
|
+
description: 'Components use BEM naming: fd-{component}, fd-{component}--{modifier}',
|
|
951
|
+
code: `<button class="fd-button fd-button--emphasized">Click Me</button>
|
|
952
|
+
<input class="fd-input" type="text" placeholder="Enter text">`,
|
|
953
|
+
language: 'html'
|
|
954
|
+
}
|
|
955
|
+
],
|
|
956
|
+
completeExample: `<!DOCTYPE html>
|
|
957
|
+
<html lang="en">
|
|
958
|
+
<head>
|
|
959
|
+
<meta charset="UTF-8">
|
|
960
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
961
|
+
<title>Fundamental Styles - Getting Started</title>
|
|
962
|
+
|
|
963
|
+
<!-- 1. Theme base variables (required) -->
|
|
964
|
+
<link href="${primaryTheme.cdn.themeBaseUrl}" rel="stylesheet">
|
|
965
|
+
|
|
966
|
+
<!-- 2. Fundamental Styles theme customizations (required) -->
|
|
967
|
+
<link href="${primaryTheme.cdn.themeFundUrl}" rel="stylesheet">
|
|
968
|
+
|
|
969
|
+
<!-- 3. Component CSS -->
|
|
970
|
+
${cdnComponentLinks.map(l => ' ' + l).join('\n')}
|
|
971
|
+
|
|
972
|
+
<!-- 4. Base font size (required) -->
|
|
973
|
+
<style>
|
|
974
|
+
html {
|
|
975
|
+
font-size: 16px;
|
|
976
|
+
}
|
|
977
|
+
body {
|
|
978
|
+
font-family: '72', Arial, sans-serif;
|
|
979
|
+
padding: 2rem;
|
|
980
|
+
}
|
|
981
|
+
</style>
|
|
982
|
+
</head>
|
|
983
|
+
<body>
|
|
984
|
+
<h1>Hello Fundamental Styles!</h1>
|
|
985
|
+
|
|
986
|
+
<div class="fd-form-item" style="margin-bottom: 1rem;">
|
|
987
|
+
<label class="fd-form-label" for="name">Name</label>
|
|
988
|
+
<input class="fd-input" id="name" type="text" placeholder="Enter your name">
|
|
989
|
+
</div>
|
|
990
|
+
|
|
991
|
+
<button class="fd-button fd-button--emphasized">Submit</button>
|
|
992
|
+
<button class="fd-button fd-button--transparent">Cancel</button>
|
|
993
|
+
</body>
|
|
994
|
+
</html>`,
|
|
995
|
+
notes: [
|
|
996
|
+
'📌 Pin to specific version for production: https://unpkg.com/fundamental-styles@0.41.6/dist/...',
|
|
997
|
+
'⚠️ Always include BOTH theme CSS files (base variables + fundamental theme)',
|
|
998
|
+
'🎨 Fonts and icons are included automatically from @sap-theming/theming-base-content',
|
|
999
|
+
'🔗 No JavaScript required - fundamental-styles is CSS-only',
|
|
1000
|
+
selectedThemes.length > 1 ? `🎨 ${selectedThemes.length} theme${selectedThemes.length > 1 ? 's' : ''} available - see 'themes' array for alternatives` : null
|
|
1001
|
+
].filter(Boolean)
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
// NPM Instructions
|
|
1005
|
+
if (approach === 'npm' || approach === 'both') {
|
|
1006
|
+
const npmComponentImports = componentMode === 'all'
|
|
1007
|
+
? ["import 'fundamental-styles/dist/fundamental-styles.css';"]
|
|
1008
|
+
: componentList.map(c => `import 'fundamental-styles/dist/${c}.css';`);
|
|
1009
|
+
result.npm = {
|
|
1010
|
+
description: 'NPM installation for modern build tools (Webpack, Vite, Rollup, etc.)',
|
|
1011
|
+
primaryTheme: primaryTheme.theme,
|
|
1012
|
+
themes: themeInstructions.map(t => ({
|
|
1013
|
+
theme: t.theme,
|
|
1014
|
+
themeNpmBase: t.npm.themeNpmBase,
|
|
1015
|
+
themeNpmFund: t.npm.themeNpmFund
|
|
1016
|
+
})),
|
|
1017
|
+
steps: [
|
|
1018
|
+
{
|
|
1019
|
+
step: 1,
|
|
1020
|
+
title: 'Install Packages',
|
|
1021
|
+
description: 'fundamental-styles requires @sap-theming/theming-base-content for themes, fonts, and icons',
|
|
1022
|
+
commands: [
|
|
1023
|
+
'npm install fundamental-styles @sap-theming/theming-base-content'
|
|
1024
|
+
],
|
|
1025
|
+
language: 'bash'
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
step: 2,
|
|
1029
|
+
title: 'Import Theme CSS',
|
|
1030
|
+
description: selectedThemes.length > 1
|
|
1031
|
+
? `Import in your main JavaScript/TypeScript entry point (e.g., main.js, index.js, App.tsx). Showing ${primaryTheme.theme} (primary theme). See 'themes' array for ${selectedThemes.length - 1} additional theme${selectedThemes.length > 2 ? 's' : ''}.`
|
|
1032
|
+
: 'Import in your main JavaScript/TypeScript entry point (e.g., main.js, index.js, App.tsx)',
|
|
1033
|
+
code: `// 1. Theme base variables (required)
|
|
1034
|
+
import '${primaryTheme.npm.themeNpmBase}';
|
|
1035
|
+
|
|
1036
|
+
// 2. Fundamental Styles theme customizations (required)
|
|
1037
|
+
import '${primaryTheme.npm.themeNpmFund}';`,
|
|
1038
|
+
language: 'javascript'
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
step: 3,
|
|
1042
|
+
title: 'Import Component CSS',
|
|
1043
|
+
description: componentMode === 'all'
|
|
1044
|
+
? 'Import all components (larger bundle, simpler imports)'
|
|
1045
|
+
: 'Import only what you need (smaller bundle, recommended for production)',
|
|
1046
|
+
code: npmComponentImports.join('\n'),
|
|
1047
|
+
language: 'javascript'
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
step: 4,
|
|
1051
|
+
title: 'Configure Bundler for Fonts',
|
|
1052
|
+
description: 'Ensure your bundler can handle font files from node_modules',
|
|
1053
|
+
frameworks: {
|
|
1054
|
+
webpack: {
|
|
1055
|
+
description: 'Add file-loader or asset/resource rule',
|
|
1056
|
+
code: `// webpack.config.js
|
|
1057
|
+
module.exports = {
|
|
1058
|
+
module: {
|
|
1059
|
+
rules: [
|
|
1060
|
+
{
|
|
1061
|
+
test: /\\.(woff|woff2|ttf|eot|svg)$/,
|
|
1062
|
+
type: 'asset/resource'
|
|
1063
|
+
}
|
|
1064
|
+
]
|
|
1065
|
+
}
|
|
1066
|
+
};`,
|
|
1067
|
+
language: 'javascript'
|
|
1068
|
+
},
|
|
1069
|
+
vite: {
|
|
1070
|
+
description: 'Vite handles fonts automatically, no configuration needed',
|
|
1071
|
+
code: '// No configuration needed - Vite handles fonts out of the box ✅',
|
|
1072
|
+
language: 'javascript'
|
|
1073
|
+
},
|
|
1074
|
+
create_react_app: {
|
|
1075
|
+
description: 'CRA handles fonts automatically',
|
|
1076
|
+
code: '// No configuration needed - CRA handles fonts out of the box ✅',
|
|
1077
|
+
language: 'javascript'
|
|
1078
|
+
},
|
|
1079
|
+
angular: {
|
|
1080
|
+
description: 'Add font paths to angular.json assets',
|
|
1081
|
+
code: `// angular.json
|
|
1082
|
+
{
|
|
1083
|
+
"projects": {
|
|
1084
|
+
"your-app": {
|
|
1085
|
+
"architect": {
|
|
1086
|
+
"build": {
|
|
1087
|
+
"options": {
|
|
1088
|
+
"assets": [
|
|
1089
|
+
{
|
|
1090
|
+
"glob": "**/*",
|
|
1091
|
+
"input": "node_modules/@sap-theming/theming-base-content/content/Base/baseLib/${primaryTheme.theme}/fonts",
|
|
1092
|
+
"output": "/fonts"
|
|
1093
|
+
}
|
|
1094
|
+
]
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}`,
|
|
1101
|
+
language: 'json'
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
},
|
|
1105
|
+
{
|
|
1106
|
+
step: 5,
|
|
1107
|
+
title: 'Set Base Font Size',
|
|
1108
|
+
description: 'Add to your global CSS file (e.g., index.css, globals.css, styles.css)',
|
|
1109
|
+
code: `html {
|
|
1110
|
+
font-size: 16px; /* Required for proper component sizing */
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
body {
|
|
1114
|
+
font-family: '72', Arial, sans-serif;
|
|
1115
|
+
margin: 0;
|
|
1116
|
+
padding: 0;
|
|
1117
|
+
}`,
|
|
1118
|
+
language: 'css'
|
|
1119
|
+
},
|
|
1120
|
+
{
|
|
1121
|
+
step: 6,
|
|
1122
|
+
title: 'Use Components',
|
|
1123
|
+
description: 'Use fundamental-styles classes in your HTML/JSX/templates',
|
|
1124
|
+
code: `<button className="fd-button fd-button--emphasized">Click Me</button>
|
|
1125
|
+
<input className="fd-input" type="text" placeholder="Enter text" />`,
|
|
1126
|
+
language: 'jsx'
|
|
1127
|
+
}
|
|
1128
|
+
],
|
|
1129
|
+
notes: [
|
|
1130
|
+
'📦 Always install BOTH packages: fundamental-styles AND @sap-theming/theming-base-content',
|
|
1131
|
+
'⚠️ Import theme CSS before component CSS',
|
|
1132
|
+
'🎨 Fonts are located in @sap-theming/theming-base-content/content/Base/baseLib/{theme}/fonts/',
|
|
1133
|
+
'🔧 Most modern bundlers (Vite, CRA, Next.js) handle fonts automatically',
|
|
1134
|
+
'📝 For TypeScript, no @types package needed - fundamental-styles is CSS-only',
|
|
1135
|
+
selectedThemes.length > 1 ? `🎨 ${selectedThemes.length} theme${selectedThemes.length > 1 ? 's' : ''} available - see 'themes' array for alternatives` : null
|
|
1136
|
+
].filter(Boolean)
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
// Common information for both approaches
|
|
1140
|
+
result.nextSteps = {
|
|
1141
|
+
componentExplorer: 'https://sap.github.io/fundamental-styles/',
|
|
1142
|
+
documentation: [
|
|
1143
|
+
'CLAUDE.md - Quick reference for AI agents: https://github.com/SAP/fundamental-styles/blob/main/CLAUDE.md',
|
|
1144
|
+
'Component catalog (JSON): Use list_components tool',
|
|
1145
|
+
'HTML examples: Use get_html_examples tool',
|
|
1146
|
+
'Component guidance: Use get_component_guidance tool'
|
|
1147
|
+
],
|
|
1148
|
+
commonPatterns: {
|
|
1149
|
+
buttons: 'fd-button, fd-button--emphasized (primary), fd-button--transparent (ghost)',
|
|
1150
|
+
forms: 'fd-form-item + fd-form-label + fd-input/fd-checkbox/fd-radio',
|
|
1151
|
+
states: 'is-error, is-success, is-warning, is-disabled, is-selected',
|
|
1152
|
+
sizing: 'fd-{component}--compact for dense UIs',
|
|
1153
|
+
icons: 'sap-icon--{icon-name} (e.g., sap-icon--add, sap-icon--delete)'
|
|
1154
|
+
},
|
|
1155
|
+
availableThemes: [
|
|
1156
|
+
'sap_horizon (default, light)',
|
|
1157
|
+
'sap_horizon_dark',
|
|
1158
|
+
'sap_horizon_hcb (high contrast black)',
|
|
1159
|
+
'sap_horizon_hcw (high contrast white)',
|
|
1160
|
+
'sap_fiori_3 (Quartz light)',
|
|
1161
|
+
'sap_fiori_3_dark'
|
|
1162
|
+
]
|
|
1163
|
+
};
|
|
1164
|
+
result.troubleshooting = [
|
|
1165
|
+
{
|
|
1166
|
+
issue: 'Components look unstyled or broken',
|
|
1167
|
+
solution: 'Verify BOTH theme CSS files are loaded (base variables + fundamental theme)'
|
|
1168
|
+
},
|
|
1169
|
+
{
|
|
1170
|
+
issue: 'Fonts not loading',
|
|
1171
|
+
solution: 'Ensure @sap-theming/theming-base-content is installed and bundler can handle font files'
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
issue: 'Icons not showing',
|
|
1175
|
+
solution: 'Icons come from @sap-theming/theming-base-content theme CSS. Verify theme is loaded correctly.'
|
|
1176
|
+
},
|
|
1177
|
+
{
|
|
1178
|
+
issue: 'Component sizes are wrong',
|
|
1179
|
+
solution: 'Set html { font-size: 16px; } in your global CSS'
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
issue: 'CSS conflicts with existing styles',
|
|
1183
|
+
solution: 'fundamental-styles uses BEM naming (fd-*) to minimize conflicts. Check specificity issues.'
|
|
1184
|
+
}
|
|
1185
|
+
];
|
|
1186
|
+
result.additionalPackages = [
|
|
1187
|
+
{
|
|
1188
|
+
name: '@fundamental-styles/common-css',
|
|
1189
|
+
description: 'Utility classes for margins, padding, flexbox, display (sap-* classes)',
|
|
1190
|
+
install: 'npm install @fundamental-styles/common-css',
|
|
1191
|
+
usage: "import '@fundamental-styles/common-css/dist/common-css.css';"
|
|
1192
|
+
},
|
|
1193
|
+
{
|
|
1194
|
+
name: '@fundamental-styles/cx',
|
|
1195
|
+
description: 'CX-specific components (customer experience)',
|
|
1196
|
+
install: 'npm install @fundamental-styles/cx'
|
|
1197
|
+
}
|
|
1198
|
+
];
|
|
1199
|
+
return {
|
|
1200
|
+
content: [
|
|
1201
|
+
{
|
|
1202
|
+
type: 'text',
|
|
1203
|
+
text: JSON.stringify(result, null, 2)
|
|
1204
|
+
}
|
|
1205
|
+
]
|
|
1206
|
+
};
|
|
1207
|
+
}));
|
|
678
1208
|
/** Deduplicate changelog entries — collapse RC entries when the same change also appears in a stable release. */
|
|
679
1209
|
function deduplicateEntries(entries) {
|
|
680
1210
|
const stableEntries = entries.filter((e) => !e.version.includes('-'));
|