1+ <!--
2+ Category page template for XLS Standards website
3+
4+ Displays XLS standards filtered by category with:
5+ - Category-specific introduction and metadata
6+ - Interactive sortable table with all columns (except category since it's consistent)
7+ - Status badges with color coding
8+ - JavaScript-powered sorting functionality
9+ - Navigation links back to main page and other categories
10+ -->
11+ {% extends "base.html" %}
12+
13+ {% block content %}
14+ <!-- Category introduction section -->
15+ < div class ="intro ">
16+ < div class ="category-header ">
17+ < h2 > {{ category.title() }} XLS Standards</ h2 >
18+ < div class ="category-meta ">
19+ < span class ="category-badge {{ category|lower }} "> {{ category }}</ span >
20+ < span class ="count "> {{ category_docs|length }} standard{{ 's' if category_docs|length != 1 else '' }}</ span >
21+ </ div >
22+ </ div >
23+
24+ <!-- Category description -->
25+ < div class ="category-description ">
26+ {% if category|lower == 'amendment' %}
27+ < p > Amendment standards define changes to the core XRP Ledger protocol that require network consensus and activation through the amendment process.</ p >
28+ {% elif category|lower == 'community' %}
29+ < p > Community standards describe best practices, conventions, and guidelines for the XRP Ledger ecosystem that don't require protocol changes.</ p >
30+ {% elif category|lower == 'protocol' %}
31+ < p > Protocol standards specify XRP Ledger APIs, formats, and behaviors that don't require consensus changes but define how applications interact with the network.</ p >
32+ {% else %}
33+ < p > Standards in the {{ category }} category.</ p >
34+ {% endif %}
35+ </ div >
36+
37+ <!-- Navigation to other categories -->
38+ < div class ="category-nav ">
39+ < h3 > Browse by Category:</ h3 >
40+ < div class ="category-links ">
41+ < a href ="{{ base_url }}/ " class ="category-link ">
42+ < span class ="category-badge all "> All Categories</ span >
43+ < span class ="count "> {{ total_count }} standards</ span >
44+ </ a >
45+ {% for cat_name, cat_count in all_categories %}
46+ < a href ="{{ base_url }}/category/{{ cat_name|lower }}.html " class ="category-link{% if cat_name|lower == category|lower %} active{% endif %} ">
47+ < span class ="category-badge {{ cat_name|lower }} "> {{ cat_name }}</ span >
48+ < span class ="count "> {{ cat_count }} standard{{ 's' if cat_count != 1 else '' }}</ span >
49+ </ a >
50+ {% endfor %}
51+ </ div >
52+ </ div >
53+ </ div >
54+
55+ <!-- Category standards table -->
56+ < div class ="standards-table-container ">
57+ < table class ="standards-table " id ="standardsTable ">
58+ < thead >
59+ < tr >
60+ <!-- Sortable column headers - no category column since all are the same category -->
61+ < th class ="sortable " data-column ="number "> Number</ th >
62+ < th class ="sortable " data-column ="title "> Title</ th >
63+ < th class ="sortable " data-column ="author "> Author(s)</ th >
64+ < th class ="sortable " data-column ="status "> Status</ th >
65+ < th class ="sortable " data-column ="created "> Created</ th >
66+ </ tr >
67+ </ thead >
68+ < tbody >
69+ <!-- Loop through category-specific XLS documents -->
70+ {% for doc in category_docs %}
71+ < tr class ="status-{{ doc.status }} ">
72+ <!-- XLS number column with link to document -->
73+ < td class ="number-col " data-label ="Number " data-sort-value ="{{ doc.number|int }} ">
74+ < a href ="{{ base_url }}/xls/{{ doc.folder }}.html " class ="xls-link "> XLS-{{ doc.number }}</ a >
75+ </ td >
76+
77+ <!-- Document title with link -->
78+ < td class ="title-col " data-label ="Title " data-sort-value ="{{ doc.title|lower }} ">
79+ < a href ="{{ base_url }}/xls/{{ doc.folder }}.html "> {{ doc.title }}</ a >
80+ </ td >
81+
82+ <!-- Author information -->
83+ < td class ="author-col " data-label ="Author " data-sort-value ="{% for author in doc.authors %}{% if author %}{{ author[0]|lower }}{% endif %}{% if not loop.last %}, {% endif %}{% endfor %} ">
84+ {% for author in doc.authors %}
85+ < a href ="{{ author[1] }} "> {{ author[0] }}</ a > {% if not loop.last %}, {% endif %}
86+ {% endfor %}
87+ </ td >
88+
89+ <!-- Status badge with conditional styling -->
90+ < td class ="status-col " data-label ="Status " data-sort-value ="{{ doc.status|lower }} ">
91+ < span class ="status-badge {{doc.status|lower}} "> {{ doc.status.title() }}</ span >
92+ </ td >
93+
94+ <!-- Created date column -->
95+ < td class ="created-col " data-label ="Created " data-sort-value ="{{ doc.created }} ">
96+ {{ doc.created }}
97+ </ td >
98+ </ tr >
99+ {% endfor %}
100+ </ tbody >
101+ </ table >
102+ </ div >
103+ {% endblock %}
104+
105+ {% block scripts %}
106+ <!-- JavaScript for interactive table sorting functionality -->
107+ < script >
108+ document . addEventListener ( 'DOMContentLoaded' , function ( ) {
109+ const table = document . getElementById ( 'standardsTable' ) ;
110+ const headers = table . querySelectorAll ( 'th.sortable' ) ;
111+ // Default sort: reverse numerical order (later standards more relevant)
112+ let currentSort = { column : 'number' , direction : 'desc' } ;
113+
114+ // Set initial sort indicator on the Number column
115+ const numberHeader = table . querySelector ( 'th[data-column="number"]' ) ;
116+ if ( numberHeader ) numberHeader . classList . add ( 'sort-desc' ) ;
117+
118+ // Add click event listeners to all sortable headers
119+ headers . forEach ( header => {
120+ header . addEventListener ( 'click' , function ( ) {
121+ const column = this . dataset . column ;
122+ let direction = 'asc' ;
123+
124+ // Toggle direction if clicking the same column
125+ if ( currentSort . column === column && currentSort . direction === 'asc' ) {
126+ direction = 'desc' ;
127+ }
128+
129+ // Perform the sort and update UI indicators
130+ sortTable ( column , direction ) ;
131+ updateSortIndicators ( this , direction ) ;
132+
133+ // Update current sort state
134+ currentSort = { column, direction} ;
135+ } ) ;
136+ } ) ;
137+
138+ /**
139+ * Sort the table by the specified column and direction
140+ */
141+ function sortTable ( column , direction ) {
142+ const tbody = table . querySelector ( 'tbody' ) ;
143+ const rows = Array . from ( tbody . querySelectorAll ( 'tr' ) ) ;
144+
145+ // Sort rows based on data-sort-value attributes
146+ rows . sort ( ( a , b ) => {
147+ let aVal , bVal ;
148+
149+ // Special handling for numerical sorting of XLS numbers and dates
150+ if ( column === 'number' ) {
151+ aVal = parseInt ( a . querySelector ( `td[data-label="${ column . charAt ( 0 ) . toUpperCase ( ) + column . slice ( 1 ) } "]` ) . dataset . sortValue ) ;
152+ bVal = parseInt ( b . querySelector ( `td[data-label="${ column . charAt ( 0 ) . toUpperCase ( ) + column . slice ( 1 ) } "]` ) . dataset . sortValue ) ;
153+ } else if ( column === 'created' ) {
154+ // Sort by date - data is already in YYYY-MM-DD format which sorts correctly as strings
155+ aVal = a . querySelector ( `td[data-label="${ column . charAt ( 0 ) . toUpperCase ( ) + column . slice ( 1 ) } "]` ) . dataset . sortValue ;
156+ bVal = b . querySelector ( `td[data-label="${ column . charAt ( 0 ) . toUpperCase ( ) + column . slice ( 1 ) } "]` ) . dataset . sortValue ;
157+ } else {
158+ // Text-based sorting for other columns
159+ aVal = a . querySelector ( `td[data-label="${ column . charAt ( 0 ) . toUpperCase ( ) + column . slice ( 1 ) } "]` ) . dataset . sortValue ;
160+ bVal = b . querySelector ( `td[data-label="${ column . charAt ( 0 ) . toUpperCase ( ) + column . slice ( 1 ) } "]` ) . dataset . sortValue ;
161+ }
162+
163+ // Apply sort direction
164+ if ( direction === 'asc' ) {
165+ return aVal > bVal ? 1 : - 1 ;
166+ } else {
167+ return aVal < bVal ? 1 : - 1 ;
168+ }
169+ } ) ;
170+
171+ // Re-append sorted rows to the table body
172+ rows . forEach ( row => tbody . appendChild ( row ) ) ;
173+ }
174+
175+ /**
176+ * Update visual sort indicators in column headers
177+ */
178+ function updateSortIndicators ( activeHeader , direction ) {
179+ // Clear all existing sort indicators
180+ headers . forEach ( h => {
181+ h . classList . remove ( 'sort-asc' , 'sort-desc' ) ;
182+ } ) ;
183+
184+ // Add indicator to the active header
185+ activeHeader . classList . add ( `sort-${ direction } ` ) ;
186+ }
187+ } ) ;
188+ </ script >
189+ {% endblock %}
0 commit comments