testio-tailwind 3.21.0 → 3.22.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/AI_DESIGN_SYSTEM_REFERENCE.md +2407 -0
- package/package.json +1 -1
- package/src/_data/navigation.json +4 -0
- package/src/_includes/header.njk +8 -8
- package/src/_includes/page-with-sidebar.njk +10 -1
- package/src/assets/scripts/app.js +27 -0
- package/src/assets/stylesheets/components/designsystem/designsystem-styles.css +4 -2
- package/src/assets/stylesheets/components/tables.css +4 -0
- package/src/pages/buttons/block.haml +1 -0
- package/src/pages/buttons/button_group.haml +1 -0
- package/src/pages/buttons/buttons-lg.haml +1 -0
- package/src/pages/buttons/buttons-round.haml +1 -0
- package/src/pages/buttons/buttons-sm.haml +1 -0
- package/src/pages/buttons/buttons-xl.haml +1 -0
- package/src/pages/buttons/buttons.haml +1 -0
- package/src/pages/buttons/buttons_input.haml +4 -0
- package/src/pages/buttons/dropdown-menu.haml +2 -11
- package/src/pages/buttons/square-buttons.haml +15 -0
- package/src/pages/components/alerts.haml +1 -0
- package/src/pages/components/banner_cards.haml +1 -0
- package/src/pages/components/card_badges.haml +8 -7
- package/src/pages/components/cards.haml +15 -22
- package/src/pages/components/cards_customer.haml +1 -0
- package/src/pages/components/cards_fixedwidth.haml +7 -0
- package/src/pages/components/cards_iconheader.haml +1 -0
- package/src/pages/components/cards_tester.haml +1 -0
- package/src/pages/components/descriptionlist.haml +12 -3
- package/src/pages/components/devices.haml +1 -0
- package/src/pages/components/drawer.haml +1 -0
- package/src/pages/components/drawer_filter.haml +1 -0
- package/src/pages/components/emptystate.haml +2 -0
- package/src/pages/{buttons → components}/info_popover.haml +2 -1
- package/src/pages/components/listitem_with_actionbar.haml +1 -0
- package/src/pages/components/listitem_with_footer.haml +1 -0
- package/src/pages/components/listitems.haml +1 -0
- package/src/pages/components/listitems_badge.haml +1 -0
- package/src/pages/components/listitems_collapsable.haml +1 -0
- package/src/pages/components/listitems_nested.haml +1 -0
- package/src/pages/components/listitems_selectable.haml +1 -0
- package/src/pages/components/loading_spinner.haml +1 -0
- package/src/pages/components/metasidebar.haml +1 -0
- package/src/pages/components/modal_details.haml +3 -1
- package/src/pages/components/notifications.haml +2 -1
- package/src/pages/components/user_item.haml +1 -0
- package/src/pages/forms/attachments.pug +71 -0
- package/src/pages/forms/checkboxes.haml +1 -0
- package/src/pages/forms/checkboxes_devices.haml +1 -0
- package/src/pages/forms/date-time.haml +1 -0
- package/src/pages/forms/dropzone.pug +38 -0
- package/src/pages/forms/flatpickr.haml +1 -1
- package/src/pages/forms/form-addon.haml +1 -0
- package/src/pages/forms/form-card.haml +1 -0
- package/src/pages/forms/form_grid.haml +1 -0
- package/src/pages/forms/form_hint.haml +1 -0
- package/src/pages/forms/forms.haml +1 -0
- package/src/pages/forms/radiobuttons.haml +1 -0
- package/src/pages/forms/rating_scale.haml +1 -0
- package/src/pages/forms/search.haml +1 -0
- package/src/pages/forms/selectable_token.haml +1 -0
- package/src/pages/forms/selectable_token_browsers.haml +1 -0
- package/src/pages/forms/selectable_token_lg.haml +1 -0
- package/src/pages/forms/selectable_token_xl.haml +1 -0
- package/src/pages/forms/textarea.haml +4 -0
- package/src/pages/forms/toggle-buttons.haml +1 -0
- package/src/pages/forms/toggle-switch.haml +1 -0
- package/src/pages/forms/trix_editor.pug +1 -0
- package/src/pages/icons/bug-icons.haml +1 -0
- package/src/pages/icons/index.njk +18 -14
- package/src/pages/icons/status-icons.haml +1 -0
- package/src/pages/layout/app_layout.haml +2 -0
- package/src/pages/layout/margins.haml +1 -0
- package/src/pages/layout/max_width.haml +2 -1
- package/src/pages/layout/paddings.haml +1 -0
- package/src/pages/layout/spacing.haml +1 -0
- package/src/pages/{examples → layouts}/agenticqa_splitview.haml +1 -1
- package/src/pages/layouts/layout-actionbar.haml +45 -0
- package/src/pages/{examples → layouts}/layout-basic.haml +3 -2
- package/src/pages/{examples → layouts}/layout-chat.haml +3 -2
- package/src/pages/{examples/layout-sidebar-actionbar-metasidebar.haml → layouts/layout-chatwindow.haml} +3 -2
- package/src/pages/{examples → layouts}/layout-customer.haml +3 -2
- package/src/pages/{examples → layouts}/layout-form-sidebar-actionbar-metasidebar.haml +5 -228
- package/src/pages/{examples → layouts}/layout-manager.haml +3 -2
- package/src/pages/{examples → layouts}/layout-metasidebar.haml +3 -2
- package/src/pages/{examples → layouts}/layout-sidebar.haml +3 -2
- package/src/pages/{examples → layouts}/layout-tester.haml +3 -2
- package/src/pages/{examples → layouts}/splitview-metasidebar.haml +3 -3
- package/src/pages/{examples → layouts}/splitview-testcases.haml +2 -2
- package/src/pages/{examples → layouts}/splitview.haml +3 -3
- package/src/pages/navigation/header-manager.haml +1 -0
- package/src/pages/navigation/header-tester.haml +1 -0
- package/src/pages/navigation/header.haml +1 -0
- package/src/pages/navigation/header_customer.haml +1 -0
- package/src/pages/navigation/header_tester_epam.haml +1 -0
- package/src/pages/navigation/product_dropdown.haml +2 -0
- package/src/pages/navigation/radio_tabs.haml +1 -0
- package/src/pages/navigation/sidebar-manager.haml +2 -1
- package/src/pages/navigation/sidebar-tester-elements.haml +1 -0
- package/src/pages/navigation/sidebar-tester-seatlimitation.haml +1 -1
- package/src/pages/navigation/sidebar-tester.haml +1 -1
- package/src/pages/navigation/sidebar.haml +1 -0
- package/src/pages/navigation/sidebar_collapsables.haml +1 -0
- package/src/pages/navigation/sidebar_customer.haml +1 -0
- package/src/pages/navigation/tabnavigation.haml +1 -0
- package/src/pages/navigation/tabnavigation_actions.haml +1 -0
- package/src/pages/navigation/tabnavigation_pills.haml +1 -0
- package/src/pages/navigation/tabnavigation_sm.haml +1 -0
- package/src/pages/navigation/test-header-tester.haml +2 -0
- package/src/pages/tables/index.njk +7 -0
- package/src/pages/tables/tables-cellstyle.haml +38 -0
- package/src/pages/tables/tables-grid.haml +31 -0
- package/src/pages/tables/tables.haml +16 -0
- package/src/pages/tables/tables_alternating.haml +27 -0
- package/src/pages/tables/tables_borders.haml +22 -0
- package/src/pages/tables/tables_cells.haml +50 -0
- package/src/pages/tables/tables_footer.haml +27 -0
- package/src/pages/tables/tables_formrow.haml +31 -0
- package/src/pages/tables/tables_header.haml +22 -0
- package/src/pages/{components → tables}/tables_linked.haml +11 -10
- package/src/pages/typography/link_with_icon.haml +10 -2
- package/src/pages/typography/linked_icon.haml +6 -0
- package/src/pages/typography/section_header.haml +1 -0
- package/src/pages/typography/section_header_actions.haml +1 -0
- package/src/pages/typography/text_with_icon.haml +3 -2
- package/utils/filters.js +161 -0
- package/CLAUDE_DESIGN_SYSTEM_REFERENCE.md +0 -1978
- package/src/pages/buttons/link-with-icon.haml +0 -13
- package/src/pages/components/tables-cellstyle.pug +0 -285
- package/src/pages/components/tables-grid.pug +0 -258
- package/src/pages/components/tables.haml +0 -57
- package/src/pages/components/tables_cells.pug +0 -57
- package/src/pages/components/tables_formrow.haml +0 -55
- package/src/pages/examples/layout-actionbar.haml +0 -268
- package/src/pages/examples/layout-sidebar-actionbar.haml +0 -308
- package/src/pages/forms/uploads.pug +0 -101
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: tables
|
|
3
|
+
title: Standard table
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
%p.mb-heading A standard table with basic styling and a cell with buttons.
|
|
7
|
+
%table.table
|
|
8
|
+
%tr
|
|
9
|
+
%td Cell content
|
|
10
|
+
%td Cell content
|
|
11
|
+
%td Cell content
|
|
12
|
+
%tr
|
|
13
|
+
%td Cell content Lorem ipsum dolor sit amet, consetetur sadipscing.
|
|
14
|
+
%td Cell content
|
|
15
|
+
%td.cell-with-buttons
|
|
16
|
+
%button.btn.btn-primary action
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: tables
|
|
3
|
+
title: Striped rows
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
%p.mb-heading Table with alternating background colors for rows
|
|
7
|
+
%table.table.table-striped
|
|
8
|
+
%tr
|
|
9
|
+
%td Cell content
|
|
10
|
+
%td Cell content
|
|
11
|
+
%td.cell-with-buttons
|
|
12
|
+
%button.btn.btn-primary action
|
|
13
|
+
%tr
|
|
14
|
+
%td Cell content
|
|
15
|
+
%td Cell content
|
|
16
|
+
%td.cell-with-buttons
|
|
17
|
+
%button.btn.btn-primary action
|
|
18
|
+
%tr
|
|
19
|
+
%td Cell content Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
|
20
|
+
%td Cell content
|
|
21
|
+
%td.cell-with-buttons
|
|
22
|
+
%button.btn.btn-primary action
|
|
23
|
+
%tr
|
|
24
|
+
%td Cell content
|
|
25
|
+
%td Cell content
|
|
26
|
+
%td.cell-with-buttons
|
|
27
|
+
%button.btn.btn-primary action
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: tables
|
|
3
|
+
title: Borders
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
%p.mb-heading Table with borders
|
|
7
|
+
%table.table.table-bordered
|
|
8
|
+
%tr
|
|
9
|
+
%td Cell content
|
|
10
|
+
%td Cell content
|
|
11
|
+
%td.cell-with-buttons
|
|
12
|
+
%button.btn.btn-primary action
|
|
13
|
+
%tr
|
|
14
|
+
%td Cell content
|
|
15
|
+
%td Cell content
|
|
16
|
+
%td.cell-with-buttons
|
|
17
|
+
%button.btn.btn-primary action
|
|
18
|
+
%tr
|
|
19
|
+
%td Cell content Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
|
20
|
+
%td Cell content
|
|
21
|
+
%td.cell-with-buttons
|
|
22
|
+
%button.btn.btn-primary action
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: tables
|
|
3
|
+
title: Cell behavior
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
%p.mb-heading
|
|
7
|
+
Using the class
|
|
8
|
+
%code.tag table-standard
|
|
9
|
+
will make the last cell in a row take up all the available space. All previous cells will be as wide as their content.
|
|
10
|
+
|
|
11
|
+
%table.table-standard.table-cellstyle
|
|
12
|
+
%tbody
|
|
13
|
+
%tr
|
|
14
|
+
%td A cell with some lorem ipsum
|
|
15
|
+
%td Cell content
|
|
16
|
+
%td A small cell
|
|
17
|
+
%tr
|
|
18
|
+
%td This cell will take as much space as it's content
|
|
19
|
+
%td Cell content
|
|
20
|
+
%td The last cell will take up all the free space
|
|
21
|
+
.py-sm
|
|
22
|
+
%table.table-standard.table-cellstyle
|
|
23
|
+
%tbody
|
|
24
|
+
%tr
|
|
25
|
+
%td.cell-full-width
|
|
26
|
+
Add
|
|
27
|
+
%code.tag.bg-gray-light .cell-full-width
|
|
28
|
+
to let a cell take all the available space.
|
|
29
|
+
%td.wrap.min-w-12
|
|
30
|
+
Add
|
|
31
|
+
%code.tag.bg-gray-light .wrap
|
|
32
|
+
to allow line breaks within a cell.
|
|
33
|
+
%td Another cell content
|
|
34
|
+
%td € 40.00
|
|
35
|
+
%tr
|
|
36
|
+
%td.cell-full-width.pre
|
|
37
|
+
%p Add
|
|
38
|
+
%code.tag.bg-gray-light .pre
|
|
39
|
+
%br
|
|
40
|
+
to show preformatted white space.
|
|
41
|
+
| Multi
|
|
42
|
+
| Line
|
|
43
|
+
| textbox
|
|
44
|
+
| Cat and dog
|
|
45
|
+
%td.wrap.min-w-spacing-2xl
|
|
46
|
+
Wrapping cells need a
|
|
47
|
+
%code.tag.bg-gray-light .min-w
|
|
48
|
+
rule to not be squished.
|
|
49
|
+
%td Another cell content
|
|
50
|
+
%td € 999.00
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: tables
|
|
3
|
+
title: Footer
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
%p.mb-heading Table with header and footer
|
|
7
|
+
%table.table.table-bordered.table-striped
|
|
8
|
+
%thead
|
|
9
|
+
%th Table header
|
|
10
|
+
%th Table header
|
|
11
|
+
%th Table header
|
|
12
|
+
%tbody
|
|
13
|
+
%tr
|
|
14
|
+
%td Cell content Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
|
15
|
+
%td Cell content
|
|
16
|
+
%td.cell-with-buttons
|
|
17
|
+
%button.btn.btn-primary action
|
|
18
|
+
%tr
|
|
19
|
+
%td Cell content
|
|
20
|
+
%td Cell content Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
|
21
|
+
%td.cell-with-buttons
|
|
22
|
+
%button.btn.btn-primary action
|
|
23
|
+
%tfoot
|
|
24
|
+
%tr
|
|
25
|
+
%td Table footer
|
|
26
|
+
%td Table footer
|
|
27
|
+
%td Table footer
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: tables
|
|
3
|
+
title: Table within form
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
%p.mb-xs Tables cannot contain form elements, instead wrap the whole table with a form element.
|
|
7
|
+
|
|
8
|
+
%form
|
|
9
|
+
%table.table.table-bordered.align-top
|
|
10
|
+
%tbody
|
|
11
|
+
%tr
|
|
12
|
+
%td
|
|
13
|
+
%select.tom-select.min-w-spacing-3xl{placeholder: "Please select"}
|
|
14
|
+
%option{value: ""}
|
|
15
|
+
%option{value:"Option 1"} Option 1
|
|
16
|
+
%option{value:"Option 2"} Option 2
|
|
17
|
+
%option{value:"Option 3"} Option 3
|
|
18
|
+
%option{value:"Option 4"} ABC
|
|
19
|
+
%option{value:"Option 5"} DEF
|
|
20
|
+
%option{value:"Option 6"} WHY
|
|
21
|
+
%option{value:"Option 7"} XYZ
|
|
22
|
+
%td
|
|
23
|
+
%input.form-control.min-w-spacing-3xl{type:'text', placeholder:"Add min-w to avoid squishing"}
|
|
24
|
+
%td
|
|
25
|
+
%textarea.form-control.min-w-spacing-3xl{rows:'1', placeholder:"Text area with min-w"}
|
|
26
|
+
%td.text-right
|
|
27
|
+
.btn-group.ml-auto
|
|
28
|
+
%button.btn.btn-success.btn-square
|
|
29
|
+
.icon.icon-check
|
|
30
|
+
%button.btn.btn-danger.btn-square
|
|
31
|
+
.icon.icon-cross
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: tables
|
|
3
|
+
title: Header
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
%p.mb-heading Table with header
|
|
7
|
+
%table.table.table-bordered.table-striped
|
|
8
|
+
%thead
|
|
9
|
+
%th Table header
|
|
10
|
+
%th Table header
|
|
11
|
+
%th Table header
|
|
12
|
+
%tbody
|
|
13
|
+
%tr
|
|
14
|
+
%td Cell content Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
|
15
|
+
%td Cell content
|
|
16
|
+
%td
|
|
17
|
+
%button.btn.btn-primary action
|
|
18
|
+
%tr
|
|
19
|
+
%td Cell content
|
|
20
|
+
%td Cell content Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
|
21
|
+
%td
|
|
22
|
+
%button.btn.btn-primary action
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
---
|
|
2
|
-
tags:
|
|
3
|
-
title:
|
|
2
|
+
tags: tables
|
|
3
|
+
title: Linked cells and rows
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
%p.mb-heading
|
|
7
|
-
Individual cells can be linked with
|
|
8
|
-
%
|
|
9
|
-
|
|
10
|
-
%table.table.table-bordered
|
|
11
|
-
%thead
|
|
12
|
-
%th Table header
|
|
13
|
-
%th Table header
|
|
14
|
-
%th Table header
|
|
7
|
+
%span Individual cells can be linked with Javascript. Add the class
|
|
8
|
+
%code.tag .linked-cell
|
|
9
|
+
%span to highlight it on hover.
|
|
10
|
+
%table.table.table-bordered
|
|
15
11
|
%tbody
|
|
16
12
|
%tr
|
|
17
13
|
%td.linked-cell{onclick: "location.href='https://test.io'"} Linked cell
|
|
18
14
|
%td.linked-cell{onclick: "location.href='https://test.io'"} Linked cell
|
|
19
15
|
%td.cell-with-buttons
|
|
20
16
|
%a.btn.btn-primary{href:"#"} action
|
|
17
|
+
%p.mb-heading
|
|
18
|
+
%span If you want to highlight a whole row, but still have action buttons, use the class
|
|
19
|
+
%code.tag .highlight-parent-row.
|
|
20
|
+
%table.table.table-bordered
|
|
21
|
+
%tbody
|
|
21
22
|
%tr
|
|
22
23
|
%td.highlight-parent-row{onclick: "location.href='https://test.io'"} Highlight parent
|
|
23
24
|
%td.highlight-parent-row{onclick: "location.href='https://test.io'"} Highlight parent
|
|
@@ -3,10 +3,18 @@ tags: typography
|
|
|
3
3
|
title: Link with icon
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
%p.mb-heading This component provides a solution for the common usecase to have links with icons.
|
|
6
7
|
%a.link-with-icon{href:""}
|
|
7
8
|
.icon.icon-exclamation-circle
|
|
8
|
-
|
|
9
|
+
Link text
|
|
9
10
|
.pt-xs
|
|
10
11
|
%a.link-with-icon{href:""}
|
|
11
12
|
.icon.icon-exclamation-circle
|
|
12
|
-
|
|
13
|
+
A longer link text that might wrap onto multiple lines to demonstrate proper alignment of the icon with the text content.
|
|
14
|
+
%p.my-heading As an alternative consider the use of ghost buttons.
|
|
15
|
+
%a.btn.btn-ghost{href:""}
|
|
16
|
+
.icon.icon-exclamation-circle.mr-icon-spacing
|
|
17
|
+
Button
|
|
18
|
+
%a.btn.btn-ghost.btn-sm{href:""}
|
|
19
|
+
.icon.icon-exclamation-circle.mr-icon-spacing
|
|
20
|
+
Button SM
|
|
@@ -3,8 +3,14 @@ tags: typography
|
|
|
3
3
|
title: Linked icon
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
%p.mb-heading This component provides a solution for the common usecase to have linked icons.
|
|
6
7
|
%a.linked-icon{href:""}
|
|
7
8
|
.icon.icon-exclamation-circle
|
|
8
9
|
.pt-xs
|
|
9
10
|
%a.linked-icon{href:""}
|
|
10
11
|
.icon.icon-exclamation-circle-filled
|
|
12
|
+
%p.my-heading As an alternative consider the use of square ghost buttons. They offer a larger clickable area.
|
|
13
|
+
%a.btn.btn-square.btn-ghost{href:""}
|
|
14
|
+
.icon.icon-exclamation-circle
|
|
15
|
+
%a.btn.btn-square.btn-ghost.btn-sm{href:""}
|
|
16
|
+
.icon.icon-exclamation-circle
|
|
@@ -3,10 +3,11 @@ tags: typography
|
|
|
3
3
|
title: Text with icon
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
%p.mb-heading This component provides a solution for the common usecase to have text with icons.
|
|
6
7
|
.text-with-icon
|
|
7
8
|
.icon.icon-exclamation-circle
|
|
8
|
-
|
|
9
|
+
Example text
|
|
9
10
|
.pt-xs
|
|
10
11
|
.text-with-icon
|
|
11
12
|
.icon.icon-exclamation-circle
|
|
12
|
-
|
|
13
|
+
A longer example text that might wrap onto multiple lines to demonstrate proper alignment of the icon with the text content.
|
package/utils/filters.js
CHANGED
|
@@ -1,11 +1,172 @@
|
|
|
1
1
|
|
|
2
2
|
const { DateTime } = require('luxon')
|
|
3
3
|
|
|
4
|
+
// HTML to HAML converter with proper indentation
|
|
5
|
+
function htmlToHaml(html) {
|
|
6
|
+
let haml = '';
|
|
7
|
+
let currentIndent = 0;
|
|
8
|
+
|
|
9
|
+
// Remove leading/trailing whitespace
|
|
10
|
+
html = html.trim();
|
|
11
|
+
|
|
12
|
+
// Tokenize HTML
|
|
13
|
+
const tokens = tokenizeHtml(html);
|
|
14
|
+
|
|
15
|
+
// Process tokens
|
|
16
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
17
|
+
const token = tokens[i];
|
|
18
|
+
|
|
19
|
+
if (token.type === 'openTag') {
|
|
20
|
+
const hamlTag = tagToHaml(token.tag, token.attrs);
|
|
21
|
+
haml += getIndent(currentIndent) + hamlTag;
|
|
22
|
+
|
|
23
|
+
// Check if this is a self-closing or void element
|
|
24
|
+
if (token.selfClosing || isVoidElement(token.tag)) {
|
|
25
|
+
haml += '\n';
|
|
26
|
+
} else {
|
|
27
|
+
haml += '\n';
|
|
28
|
+
currentIndent++;
|
|
29
|
+
}
|
|
30
|
+
} else if (token.type === 'closeTag') {
|
|
31
|
+
currentIndent = Math.max(0, currentIndent - 1);
|
|
32
|
+
} else if (token.type === 'text') {
|
|
33
|
+
const text = token.content.trim();
|
|
34
|
+
if (text) {
|
|
35
|
+
haml += getIndent(currentIndent) + text + '\n';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return haml.trim();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Tokenize HTML into an array of tokens
|
|
44
|
+
function tokenizeHtml(html) {
|
|
45
|
+
const tokens = [];
|
|
46
|
+
let i = 0;
|
|
47
|
+
|
|
48
|
+
while (i < html.length) {
|
|
49
|
+
if (html[i] === '<') {
|
|
50
|
+
const tagEnd = html.indexOf('>', i);
|
|
51
|
+
if (tagEnd === -1) break;
|
|
52
|
+
|
|
53
|
+
const tagContent = html.substring(i + 1, tagEnd);
|
|
54
|
+
|
|
55
|
+
if (tagContent.startsWith('/')) {
|
|
56
|
+
// Closing tag
|
|
57
|
+
const tagName = tagContent.substring(1).trim();
|
|
58
|
+
tokens.push({ type: 'closeTag', tag: tagName });
|
|
59
|
+
} else if (tagContent.startsWith('!')) {
|
|
60
|
+
// Comment or doctype - skip
|
|
61
|
+
i = tagEnd + 1;
|
|
62
|
+
continue;
|
|
63
|
+
} else {
|
|
64
|
+
// Opening tag
|
|
65
|
+
const selfClosing = tagContent.endsWith('/');
|
|
66
|
+
const cleanContent = selfClosing ? tagContent.slice(0, -1) : tagContent;
|
|
67
|
+
const parts = cleanContent.trim().split(/\s+/);
|
|
68
|
+
const tagName = parts[0];
|
|
69
|
+
const attrString = cleanContent.substring(tagName.length).trim();
|
|
70
|
+
|
|
71
|
+
tokens.push({
|
|
72
|
+
type: 'openTag',
|
|
73
|
+
tag: tagName,
|
|
74
|
+
attrs: attrString,
|
|
75
|
+
selfClosing: selfClosing
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
i = tagEnd + 1;
|
|
80
|
+
} else {
|
|
81
|
+
// Text content
|
|
82
|
+
const nextTag = html.indexOf('<', i);
|
|
83
|
+
const textEnd = nextTag === -1 ? html.length : nextTag;
|
|
84
|
+
const text = html.substring(i, textEnd);
|
|
85
|
+
|
|
86
|
+
if (text.trim()) {
|
|
87
|
+
tokens.push({ type: 'text', content: text });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
i = textEnd;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return tokens;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Convert a tag and its attributes to HAML format
|
|
98
|
+
function tagToHaml(tag, attrString) {
|
|
99
|
+
let result = '%' + tag;
|
|
100
|
+
|
|
101
|
+
if (!attrString) {
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const classes = [];
|
|
106
|
+
const ids = [];
|
|
107
|
+
const attrs = {};
|
|
108
|
+
|
|
109
|
+
// Parse attributes
|
|
110
|
+
const attrRegex = /(\w+(?:-\w+)*(?::\w+)*)\s*=\s*["']([^"']*)["']|(\w+(?:-\w+)*(?::\w+)*)/g;
|
|
111
|
+
let match;
|
|
112
|
+
|
|
113
|
+
while ((match = attrRegex.exec(attrString)) !== null) {
|
|
114
|
+
if (match[1]) {
|
|
115
|
+
const name = match[1];
|
|
116
|
+
const value = match[2];
|
|
117
|
+
|
|
118
|
+
if (name === 'class') {
|
|
119
|
+
classes.push(...value.split(/\s+/));
|
|
120
|
+
} else if (name === 'id') {
|
|
121
|
+
ids.push(value);
|
|
122
|
+
} else if (name !== 'type' || tag !== 'input') {
|
|
123
|
+
// Skip type attribute for input tags as they're implicit
|
|
124
|
+
attrs[name] = value;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Build HAML tag with classes and IDs
|
|
130
|
+
if (ids.length > 0) {
|
|
131
|
+
result += '#' + ids.join('.');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (classes.length > 0) {
|
|
135
|
+
result += '.' + classes.join('.');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Add other attributes
|
|
139
|
+
if (Object.keys(attrs).length > 0) {
|
|
140
|
+
const attrPairs = Object.entries(attrs)
|
|
141
|
+
.map(([k, v]) => `${k}:'${v}'`)
|
|
142
|
+
.join(', ');
|
|
143
|
+
result += `{${attrPairs}}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Check if tag is a void element (self-closing)
|
|
150
|
+
function isVoidElement(tag) {
|
|
151
|
+
const voidElements = ['br', 'hr', 'img', 'input', 'meta', 'link', 'area', 'base', 'col', 'embed', 'source', 'track', 'wbr'];
|
|
152
|
+
return voidElements.includes(tag.toLowerCase());
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Get indentation string
|
|
156
|
+
function getIndent(level) {
|
|
157
|
+
return ' '.repeat(level);
|
|
158
|
+
}
|
|
159
|
+
|
|
4
160
|
module.exports = {
|
|
5
161
|
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
|
|
6
162
|
htmlDateString: (dateObj) => {
|
|
7
163
|
return DateTime.fromJSDate(dateObj, {
|
|
8
164
|
zone: 'utc'
|
|
9
165
|
}).toFormat('yyyy-LL-dd');
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
// Convert HTML to HAML format
|
|
169
|
+
convertToHaml: (html) => {
|
|
170
|
+
return htmlToHaml(html);
|
|
10
171
|
}
|
|
11
172
|
}
|