Skip to content

Commit e7a7479

Browse files
committed
Improve tag management and add Others category for uncategorized tags
- Remove duplicate tags in app-card template and HTML (use single tags parameter) - Add global .hidden CSS class for proper element hiding - Add Others category in JavaScript to display uncategorized tags (shown only when not empty) - Update tag categories with missing tags: direct, continuation, conjugate-points, energy-optimization, production-regeneration, singular-control, turnpike - Add automatic color alternation via JavaScript (red-green-purple pattern) - Add Others section in filter sidebar (hidden by default)
1 parent d9e71f8 commit e7a7479

4 files changed

Lines changed: 119 additions & 36 deletions

File tree

_includes/app-card.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
<a class="app-card" href="{{ include.url }}" style="--app-color: {{ include.color | default: '#CB3C33' }};" data-tags="{{ include.tags }}">
1+
<a class="app-card" href="{{ include.url }}" style="--app-color: {{ include.color | default: '#CB3C33' }};" data-tags="{{ include.tags | join: ',' }}">
22
<div class="app-header">
33
<div class="app-avatar-text">{{ include.abbrev }}</div>
44
<span class="app-title">{{ include.title }}</span>
55
</div>
66
<div class="app-body">
77
<p class="app-summary">{{ include.summary }}</p>
8-
{% if include.tags_list %}
8+
{% if include.tags %}
99
<div class="app-tags">
1010
<span class="tags-label">Tags:</span>
11-
{% for tag in include.tags_list %}
11+
{% for tag in include.tags %}
1212
<span class="tag">{{ tag }}</span>
1313
{% endfor %}
1414
</div>

applications/index.md

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ custom_js:
8787
<div class="filter-bar" id="filter-bar-techniques"></div>
8888
</div>
8989

90+
<div class="filter-tags-section hidden" id="filter-section-others">
91+
<h4>Others</h4>
92+
<div class="filter-bar" id="filter-bar-others"></div>
93+
</div>
94+
9095
</div>
9196

9297
</div>
@@ -117,24 +122,22 @@ custom_js:
117122

118123
<div class="app-grid" id="app-grid">
119124

120-
{% assign tags-cov = "classical-mechanics,calculus-of-variations,lagrangian,direct-methods,indirect-methods" | split: "," %}
125+
{% assign tags-cov = "classical-mechanics,calculus-of-variations,lagrangian,shooting,continuation,conjugate-points" | split: "," %}
121126
{% include app-card.html
122127
url="https://control-toolbox.org/CalculusOfVariations.jl"
123128
abbrev="CoV"
124129
title="Calculus of variations"
125130
summary="Classical variational problems reformulated as optimal control problems and solved via direct and indirect numerical methods."
126-
tags="classical-mechanics,calculus-of-variations,lagrangian,direct-methods,indirect-methods"
127-
tags_list=tags-cov
131+
tags=tags-cov
128132
%}
129133

130-
{% assign tags-dbg = "biology,resource-allocation,switching-time,bang-bang,indirect-methods" | split: "," %}
134+
{% assign tags-dbg = "biology,resource-allocation,switching-time,bang-bang,direct" | split: "," %}
131135
{% include app-card.html
132136
url="https://agustinyabo.github.io/DiauxicGrowth.jl"
133137
abbrev="DBG"
134138
title="Diauxic bacterial growth"
135139
summary="Optimal resource allocation for bacterial growth on multiple substrates, maximizing final cell population via optimal control of metabolic fluxes."
136-
tags="biology,resource-allocation,switching-time,bang-bang,indirect-methods"
137-
tags_list=tags-dbg
140+
tags=tags-dbg
138141
%}
139142

140143
{% assign tags-grn = "biology,piecewise-linear,nonsmooth,regularization,gene-networks" | split: "," %}
@@ -143,30 +146,27 @@ custom_js:
143146
abbrev="GRN"
144147
title="PWL models of gene regulatory networks"
145148
summary="State transitions in piecewise linear models of gene regulatory networks, with a nonsmooth L¹ cost and regularization strategies (Hill and exponential)."
146-
tags="biology,piecewise-linear,nonsmooth,regularization,gene-networks"
147-
tags_list=tags-grn
149+
tags=tags-grn
148150
%}
149151

150-
{% assign tags-gprec = "preconditioning,shooting,convergence,hamiltonian,geometric-control" | split: "," %}
152+
{% assign tags-gprec = "preconditioning,shooting,convergence,geometric-control" | split: "," %}
151153
{% include app-card.html
152154
url="https://control-toolbox.org/GeometricPreconditioner.jl"
153155
abbrev="GPrec"
154156
font_size="19"
155157
title="Geometric preconditioner"
156158
summary="Geometric preconditioning of shooting methods to accelerate convergence in indirect optimal control, exploiting the structure of the Hamiltonian flow."
157-
tags="preconditioning,shooting,convergence,hamiltonian,geometric-control"
158-
tags_list=tags-gprec
159+
tags=tags-gprec
159160
%}
160161

161-
{% assign tags-lctrl = "constrained,regularization,shooting,indirect-methods,zermelo" | split: "," %}
162+
{% assign tags-lctrl = "constrained,regularization,pontryagin-maximum-principle,shooting,direct,shooting,zermelo" | split: "," %}
162163
{% include app-card.html
163164
url="https://control-toolbox.org/LossControl.jl"
164165
abbrev="LCtrl"
165166
font_size="19"
166167
title="Loss control regions in optimal control problems"
167168
summary="Optimal control problems with loss control regions where the control is frozen, solved by combining direct regularization and indirect shooting methods."
168-
tags="constrained,regularization,shooting,indirect-methods,zermelo"
169-
tags_list=tags-lctrl
169+
tags=tags-lctrl
170170
%}
171171

172172
{% assign tags-mf = "energy-optimization,production-regeneration,bang-bang,singular-control,turnpike" | split: "," %}
@@ -175,39 +175,35 @@ custom_js:
175175
abbrev="MF"
176176
title="Membrane filtration"
177177
summary="Energy-optimal control of membrane filtration processes with production-regeneration cycles, minimizing power consumption while achieving targeted permeate volume via bang-bang and singular control strategies."
178-
tags="energy-optimization,production-regeneration,bang-bang,singular-control,turnpike"
179-
tags_list=tags-mf
178+
tags=tags-mf
180179
%}
181180

182-
{% assign tags-mri = "medical-imaging,time-optimal,physics,geometric-control,bloch-equation" | split: "," %}
181+
{% assign tags-mri = "medical-imaging,time-optimal,geometric-control,direct,shooting,bloch-equation" | split: "," %}
183182
{% include app-card.html
184183
url="https://control-toolbox.org/MagneticResonanceImaging.jl"
185184
abbrev="MRI"
186185
title="Optimal control in Magnetic Resonance Imaging"
187186
summary="Time-minimal control of nuclear spin ensembles via RF pulses, with applications to contrast optimization in MRI using geometric optimal control."
188-
tags="medical-imaging,time-optimal,physics,geometric-control,bloch-equation"
189-
tags_list=tags-mri
187+
tags=tags-mri
190188
%}
191189

192-
{% assign tags-kepler = "aerospace,time-optimal,shooting,direct-methods,orbital-mechanics" | split: "," %}
190+
{% assign tags-kepler = "aerospace,time-optimal,shooting,direct,orbital-mechanics" | split: "," %}
193191
{% include app-card.html
194192
url="https://control-toolbox.org/Kepler.jl"
195193
abbrev="Kepler"
196194
font_size="19"
197195
title="Minimum time orbit transfer"
198196
summary="Minimum-time orbit transfer of a spacecraft under Kepler dynamics with thrust constraints, solved by direct and indirect methods."
199-
tags="aerospace,time-optimal,shooting,direct-methods,orbital-mechanics"
200-
tags_list=tags-kepler
197+
tags=tags-kepler
201198
%}
202199

203-
{% assign tags-sir = "epidemiology,constrained,social-distancing,public-health,ode" | split: "," %}
200+
{% assign tags-sir = "epidemiology,constrained,social-distancing,public-health,ode,direct" | split: "," %}
204201
{% include app-card.html
205202
url="https://anasxbouali.github.io/SIRcontrol.jl"
206203
abbrev="SIR"
207204
title="On the problem of minimizing the epidemic final size for SIR model via social distancing"
208205
summary="Minimizing epidemic final size in the SIR model via L¹-constrained social distancing interventions, with optimal control over a single or two time intervals."
209-
tags="epidemiology,constrained,social-distancing,public-health,ode"
210-
tags_list=tags-sir
206+
tags=tags-sir
211207
%}
212208

213209
</div>

assets/css/applications.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
margin-bottom: 0 !important;
44
}
55

6+
/* Global hidden class */
7+
.hidden {
8+
display: none !important;
9+
}
10+
611
/* Layout with sidebar */
712
.apps-layout {
813
display: grid;

assets/js/applications.js

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,23 +126,64 @@
126126
var tagCategories = {
127127
'domains': {
128128
container: document.getElementById('filter-bar-domains'),
129-
tags: ['classical-mechanics', 'biology', 'epidemiology', 'aerospace', 'medical-imaging', 'physics']
129+
tags: [
130+
'classical-mechanics',
131+
'biology',
132+
'epidemiology',
133+
'aerospace',
134+
'medical-imaging',
135+
'physics']
130136
},
131137
'methods': {
132138
container: document.getElementById('filter-bar-methods'),
133-
tags: ['direct-methods', 'indirect-methods', 'shooting', 'discretization', 'regularization']
139+
tags: [
140+
'direct-methods',
141+
'indirect-methods',
142+
'shooting',
143+
'discretization',
144+
'regularization',
145+
'continuation',
146+
'direct']
134147
},
135148
'problems': {
136149
container: document.getElementById('filter-bar-problems'),
137-
tags: ['time-optimal', 'energy-optimal', 'lagrangian', 'constrained', 'nonsmooth', 'bang-bang']
150+
tags: [
151+
'time-optimal',
152+
'energy-optimal',
153+
'energy-optimization',
154+
'lagrangian',
155+
'constrained',
156+
'nonsmooth',
157+
'bang-bang']
138158
},
139159
'concepts': {
140160
container: document.getElementById('filter-bar-concepts'),
141-
tags: ['calculus-of-variations', 'hamiltonian', 'pontryagin', 'geometric-control', 'piecewise-linear', 'ode']
161+
tags: [
162+
'calculus-of-variations',
163+
'hamiltonian',
164+
'pontryagin-maximum-principle',
165+
'geometric-control',
166+
'piecewise-linear',
167+
'ode',
168+
'conjugate-points',
169+
'singular-control',
170+
'turnpike']
142171
},
143172
'techniques': {
144173
container: document.getElementById('filter-bar-techniques'),
145-
tags: ['preconditioning', 'convergence', 'switching-time', 'state-constraints', 'resource-allocation', 'social-distancing', 'public-health', 'gene-networks', 'zermelo', 'bloch-equation', 'orbital-mechanics']
174+
tags: [
175+
'preconditioning',
176+
'convergence',
177+
'switching-time',
178+
'state-constraints',
179+
'resource-allocation',
180+
'social-distancing',
181+
'public-health',
182+
'gene-networks',
183+
'zermelo',
184+
'bloch-equation',
185+
'orbital-mechanics',
186+
'production-regeneration']
146187
}
147188
};
148189

@@ -168,20 +209,29 @@
168209
var activeFilters = new Set();
169210
var tagButtons = {};
170211

212+
// Collect all categorized tags
213+
var categorizedTags = new Set();
214+
Object.keys(tagCategories).forEach(function(categoryKey) {
215+
tagCategories[categoryKey].tags.forEach(function(tag) {
216+
categorizedTags.add(tag);
217+
});
218+
});
219+
220+
// Create buttons for categorized tags
171221
Object.keys(tagCategories).forEach(function(categoryKey) {
172222
var category = tagCategories[categoryKey];
173223
category.tags.forEach(function(tag) {
174224
if (allTags.has(tag)) {
175225
var btn = document.createElement('button');
176226
btn.className = 'filter-btn';
177-
227+
178228
var tagName = document.createElement('span');
179229
tagName.textContent = tag;
180-
230+
181231
var tagCount = document.createElement('span');
182232
tagCount.className = 'tag-count';
183233
tagCount.textContent = tagCounts[tag];
184-
234+
185235
btn.appendChild(tagName);
186236
btn.appendChild(tagCount);
187237
btn.addEventListener('click', function() { toggleFilter(tag); });
@@ -191,6 +241,38 @@
191241
});
192242
});
193243

244+
// Handle OTHERS category - uncategorized tags
245+
var othersContainer = document.getElementById('filter-bar-others');
246+
var othersSection = document.getElementById('filter-section-others');
247+
if (othersContainer && othersSection) {
248+
var othersTags = Array.from(allTags).filter(function(tag) {
249+
return !categorizedTags.has(tag);
250+
}).sort();
251+
252+
if (othersTags.length > 0) {
253+
othersTags.forEach(function(tag) {
254+
var btn = document.createElement('button');
255+
btn.className = 'filter-btn';
256+
257+
var tagName = document.createElement('span');
258+
tagName.textContent = tag;
259+
260+
var tagCount = document.createElement('span');
261+
tagCount.className = 'tag-count';
262+
tagCount.textContent = tagCounts[tag];
263+
264+
btn.appendChild(tagName);
265+
btn.appendChild(tagCount);
266+
btn.addEventListener('click', function() { toggleFilter(tag); });
267+
othersContainer.appendChild(btn);
268+
tagButtons[tag] = btn;
269+
});
270+
othersSection.classList.remove('hidden');
271+
} else {
272+
othersSection.classList.add('hidden');
273+
}
274+
}
275+
194276
function toggleFilter(tag) {
195277
if (activeFilters.has(tag)) {
196278
activeFilters.delete(tag);

0 commit comments

Comments
 (0)