Skip to content

Commit 0a7ef50

Browse files
Sander-ToonenSander Toonen
andauthored
Fix examples + Copy example button (#22)
* Copy example button * Add missing file --------- Co-authored-by: Sander Toonen <s.toonen@pro-fa.com>
1 parent 0189cf3 commit 0a7ef50

4 files changed

Lines changed: 164 additions & 122 deletions

File tree

samples/language-service-sample/app.js

Lines changed: 65 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -43,137 +43,72 @@ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e)
4343

4444
initTheme();
4545

46-
// Examples data
47-
const exampleCases = [
48-
{
49-
id: 'math',
50-
title: 'Mathematical Expression',
51-
description: 'Basic math operations with variables',
52-
expression: '(x + y) * multiplier + sqrt(16)',
53-
context: {
54-
x: 10,
55-
y: 5,
56-
multiplier: 3
57-
}
58-
},
59-
{
60-
id: 'arrays',
61-
title: 'Working with Arrays',
62-
description: 'Array functions like sum, min, max',
63-
expression: 'sum(numbers) + max(numbers) - min(numbers)',
64-
context: {
65-
numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
66-
values: [15, 25, 35]
67-
}
68-
},
69-
{
70-
id: 'objects',
71-
title: 'Object Manipulation',
72-
description: 'Access nested object properties',
73-
expression: 'user.profile.score * level.multiplier + bonus.points',
74-
context: {
75-
user: {
76-
name: "Alice",
77-
profile: {
78-
score: 85,
79-
rank: "Gold"
80-
}
81-
},
82-
level: {
83-
current: 5,
84-
multiplier: 1.5
85-
},
86-
bonus: {
87-
points: 100,
88-
active: true
89-
}
90-
}
91-
},
92-
{
93-
id: 'map-filter',
94-
title: 'Map and Filter Functions',
95-
description: 'Transform and filter data with callbacks',
96-
expression: 'sum(map(filter(items, item => item > 3), x => x * 2))',
97-
context: {
98-
items: [1, 2, 3, 4, 5, 6, 7, 8],
99-
threshold: 3
100-
}
101-
},
102-
{
103-
id: 'complex',
104-
title: 'Complex Objects',
105-
description: 'Work with deeply nested data structures',
106-
expression: 'company.departments[0].employees.length * company.settings.bonusRate + sum(map(company.departments, d => d.budget))',
107-
context: {
108-
company: {
109-
name: "TechCorp",
110-
departments: [
111-
{
112-
name: "Engineering",
113-
budget: 500000,
114-
employees: ["John", "Jane", "Bob"]
115-
},
116-
{
117-
name: "Marketing",
118-
budget: 200000,
119-
employees: ["Alice", "Carol"]
120-
}
121-
],
122-
settings: {
123-
bonusRate: 0.15,
124-
fiscalYear: 2024
125-
}
126-
}
127-
}
128-
},
129-
{
130-
id: 'data-transform',
131-
title: 'Data Transformation',
132-
description: 'Flatten nested objects and transform rows',
133-
expression: "map(f(row) = {_id: row.rowId} + flatten(row.data, ''), $event)",
134-
context: {
135-
"$event": [
136-
{"rowId": 1, "state": "saved", "data": { "InventoryId": 1256, "Description": "Bal", "Weight": { "Unit": "g", "Amount": 120 } }},
137-
{"rowId": 2, "state": "new", "data": { "InventoryId": 2344, "Description": "Basket", "Weight": { "Unit": "g", "Amount": 300 } }},
138-
{"rowId": 3, "state": "unchanged", "data": { "InventoryId": 9362, "Description": "Wood", "Weight": { "Unit": "kg", "Amount": 18 } }}
139-
]
140-
}
141-
}
142-
];
46+
// Copy example link to clipboard
47+
function copyExampleLink(exampleId, button) {
48+
const url = new URL(window.location.href);
49+
url.search = '';
50+
url.searchParams.set('example', exampleId);
51+
navigator.clipboard.writeText(url.toString()).then(() => {
52+
// Show checkmark briefly
53+
const icon = button.querySelector('svg');
54+
const originalPath = icon.innerHTML;
55+
icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />';
56+
button.classList.add('text-green-500', 'dark:text-green-400');
57+
setTimeout(() => {
58+
icon.innerHTML = originalPath;
59+
button.classList.remove('text-green-500', 'dark:text-green-400');
60+
}, 1500);
61+
});
62+
}
14363

14464
// Render examples sidebar
14565
function renderExamplesSidebar() {
14666
const examplesList = document.getElementById('examplesList');
14767
if (!examplesList) return;
14868

14969
examplesList.innerHTML = exampleCases.map(example => `
150-
<button
151-
class="example-item w-full text-left p-3 rounded-lg transition-all duration-200
152-
hover:bg-white dark:hover:bg-[#2d2d2d]
153-
hover:shadow-sm hover:border-indigo-200 dark:hover:border-[#3c3c3c]
154-
border border-transparent
155-
group"
156-
data-example-id="${example.id}"
157-
>
158-
<div class="flex items-start gap-2">
159-
<div class="flex-shrink-0 w-6 h-6 rounded bg-indigo-100 dark:bg-[#3c3c3c] flex items-center justify-center mt-0.5">
160-
<svg class="w-3.5 h-3.5 text-indigo-600 dark:text-[#569cd6]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
161-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
162-
</svg>
70+
<div class="example-container relative group/container">
71+
<button
72+
class="example-item w-full text-left p-3 rounded-lg transition-all duration-200
73+
hover:bg-white dark:hover:bg-[#2d2d2d]
74+
hover:shadow-sm hover:border-indigo-200 dark:hover:border-[#3c3c3c]
75+
border border-transparent
76+
group"
77+
data-example-id="${example.id}"
78+
>
79+
<div class="flex items-start gap-2">
80+
<div class="flex-shrink-0 w-6 h-6 rounded bg-indigo-100 dark:bg-[#3c3c3c] flex items-center justify-center mt-0.5">
81+
<svg class="w-3.5 h-3.5 text-indigo-600 dark:text-[#569cd6]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
82+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
83+
</svg>
84+
</div>
85+
<div class="flex-1 min-w-0">
86+
<p class="text-sm font-medium text-gray-800 dark:text-[#cccccc] truncate group-hover:text-indigo-600 dark:group-hover:text-[#569cd6]">
87+
${example.title}
88+
</p>
89+
<p class="text-xs text-gray-500 dark:text-[#808080] mt-0.5 line-clamp-2">
90+
${example.description}
91+
</p>
92+
</div>
16393
</div>
164-
<div class="flex-1 min-w-0">
165-
<p class="text-sm font-medium text-gray-800 dark:text-[#cccccc] truncate group-hover:text-indigo-600 dark:group-hover:text-[#569cd6]">
166-
${example.title}
167-
</p>
168-
<p class="text-xs text-gray-500 dark:text-[#808080] mt-0.5 line-clamp-2">
169-
${example.description}
170-
</p>
171-
</div>
172-
</div>
173-
</button>
94+
</button>
95+
<button
96+
class="copy-link-btn absolute top-2 right-2 p-1.5 rounded-md
97+
opacity-0 group-hover/container:opacity-100
98+
bg-gray-100 dark:bg-[#3c3c3c] hover:bg-gray-200 dark:hover:bg-[#4c4c4c]
99+
text-gray-500 dark:text-[#808080] hover:text-indigo-600 dark:hover:text-[#569cd6]
100+
transition-all duration-200"
101+
data-example-id="${example.id}"
102+
title="Copy link to example"
103+
>
104+
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
105+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
106+
</svg>
107+
</button>
108+
</div>
174109
`).join('');
175110

176-
// Add click handlers
111+
// Add click handlers for loading examples
177112
examplesList.querySelectorAll('.example-item').forEach(button => {
178113
button.addEventListener('click', () => {
179114
const exampleId = button.dataset.exampleId;
@@ -183,6 +118,15 @@ function renderExamplesSidebar() {
183118
}
184119
});
185120
});
121+
122+
// Add click handlers for copy link buttons
123+
examplesList.querySelectorAll('.copy-link-btn').forEach(button => {
124+
button.addEventListener('click', (e) => {
125+
e.stopPropagation();
126+
const exampleId = button.dataset.exampleId;
127+
copyExampleLink(exampleId, button);
128+
});
129+
});
186130
}
187131

188132
// Load example into editors
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Example cases for the language service sample
2+
const exampleCases = [
3+
{
4+
id: 'math',
5+
title: 'Mathematical Expression',
6+
description: 'Basic math operations with variables',
7+
expression: '(x + y) * multiplier + sqrt(16)',
8+
context: {
9+
x: 10,
10+
y: 5,
11+
multiplier: 3
12+
}
13+
},
14+
{
15+
id: 'arrays',
16+
title: 'Working with Arrays',
17+
description: 'Array functions like sum, min, max',
18+
expression: 'sum(numbers) + max(numbers) - min(numbers)',
19+
context: {
20+
numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
21+
values: [15, 25, 35]
22+
}
23+
},
24+
{
25+
id: 'objects',
26+
title: 'Object Manipulation',
27+
description: 'Access nested object properties',
28+
expression: 'user.profile.score * level.multiplier + bonus.points',
29+
context: {
30+
user: {
31+
name: "Alice",
32+
profile: {
33+
score: 85,
34+
rank: "Gold"
35+
}
36+
},
37+
level: {
38+
current: 5,
39+
multiplier: 1.5
40+
},
41+
bonus: {
42+
points: 100,
43+
active: true
44+
}
45+
}
46+
},
47+
{
48+
id: 'map-filter',
49+
title: 'Map and Filter Functions',
50+
description: 'Transform and filter data with callbacks',
51+
expression: 'sum(\n map(\n f(x) = x * 2, \n filter(\n f(i) = i > threshold, \n items\n )\n )\n) / length(items)',
52+
context: {
53+
items: [1, 2, 3, 4, 5, 6, 7, 8],
54+
threshold: 3
55+
}
56+
},
57+
{
58+
id: 'complex',
59+
title: 'Complex Objects',
60+
description: 'Work with deeply nested data structures',
61+
expression: 'length(company.departments[0].employees) * company.settings.bonusRate + sum(map(f(d) = d.budget, company.departments))',
62+
context: {
63+
company: {
64+
name: "TechCorp",
65+
departments: [
66+
{
67+
name: "Engineering",
68+
budget: 500000,
69+
employees: ["John", "Jane", "Bob"]
70+
},
71+
{
72+
name: "Marketing",
73+
budget: 200000,
74+
employees: ["Alice", "Carol"]
75+
}
76+
],
77+
settings: {
78+
bonusRate: 0.15,
79+
fiscalYear: 2024
80+
}
81+
}
82+
}
83+
},
84+
{
85+
id: 'data-transform',
86+
title: 'Data Transformation',
87+
description: 'Flatten nested objects and transform rows',
88+
expression: "map(f(row) = {_id: row.rowId} + flatten(row.data, ''), $event)",
89+
context: {
90+
"$event": [
91+
{"rowId": 1, "state": "saved", "data": { "InventoryId": 1256, "Description": "Bal", "Weight": { "Unit": "g", "Amount": 120 } }},
92+
{"rowId": 2, "state": "new", "data": { "InventoryId": 2344, "Description": "Basket", "Weight": { "Unit": "g", "Amount": 300 } }},
93+
{"rowId": 3, "state": "unchanged", "data": { "InventoryId": 9362, "Description": "Wood", "Weight": { "Unit": "kg", "Amount": 18 } }}
94+
]
95+
}
96+
}
97+
];

samples/language-service-sample/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ <h1 class="text-xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 dark
143143
<span>Saved to localStorage</span>
144144
</div>
145145

146+
<script src="examples.js"></script>
146147
<script src="app.js"></script>
147148
</body>
148149
</html>

samples/language-service-sample/serve-sample.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const server = http.createServer((req, res) => {
3232

3333
if (urlPath === '/' || urlPath === '/index.html') {
3434
urlPath = 'samples/language-service-sample/index.html';
35-
} else if (urlPath === '/styles.css' || urlPath === '/app.js') {
35+
} else if (urlPath === '/styles.css' || urlPath === '/app.js' || urlPath === '/examples.js') {
3636
// Serve sample-specific files from the sample folder
3737
urlPath = 'samples/language-service-sample' + urlPath;
3838
}

0 commit comments

Comments
 (0)