Просмотр исходного кода

Add segmented control component (#2087)

* Add segmented control component and update related files

* Implement segmented navigation component and update related styles

* Create grumpy-flowers-act.md

* Refactor .gitignore and move playground pages to preview directory

* Enhance segmented navigation with hover state and class support

* Refactor segmented control layout for improved responsiveness and alignment
Paweł Kuna 7 месяцев назад
Родитель
Сommit
cb278c762d

+ 6 - 0
.changeset/grumpy-flowers-act.md

@@ -0,0 +1,6 @@
+---
+"@tabler/core": patch
+"preview": patch
+---
+
+Add segmented control component

+ 1 - 1
.gitignore

@@ -20,9 +20,9 @@ node_modules/
 /components/
 /percy.sh
 /preview/pages/playground.html
-/preview/pages/playground-*.html
 /preview/pages/screenshot.html
 /preview/pages/screenshot-*.html
+/preview/pages/playground-*.html
 /preview/pages/features.html
 
 .pnp.loader.mjs

+ 1 - 0
core/scss/_core.scss

@@ -49,6 +49,7 @@
 @import "ui/ribbons";
 @import "ui/markdown";
 @import "ui/placeholder";
+@import "ui/segmented";
 @import "ui/steps";
 @import "ui/status";
 @import "ui/switch-icon";

+ 101 - 0
core/scss/ui/_segmented.scss

@@ -0,0 +1,101 @@
+.nav-segmented {
+  --#{$prefix}nav-bg: var(--#{$prefix}bg-surface-tertiary);
+  --#{$prefix}nav-padding: 2px;
+  --#{$prefix}nav-height: 2.5rem;
+  --#{$prefix}nav-gap: .25rem;
+  --#{$prefix}nav-active-bg: var(--#{$prefix}bg-surface);
+  --#{$prefix}nav-font-size: inherit;
+  --#{$prefix}nav-radius: 6px;
+
+
+  --#{$prefix}nav-link-disabled-color: var(--#{$prefix}disabled-color);
+  --#{$prefix}nav-link-gap: .25rem;
+  --#{$prefix}nav-link-padding-x: .75rem;
+  --#{$prefix}nav-link-icon-size: 1.25rem;
+  display: inline-flex;
+  flex-wrap: wrap;
+  gap: var(--#{$prefix}nav-gap);
+  padding: var(--#{$prefix}nav-padding);
+  list-style: none;
+  background: var(--#{$prefix}nav-bg);
+  border-radius: calc(var(--#{$prefix}nav-radius) + var(--#{$prefix}nav-padding));
+  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .04);
+
+  .nav-link {
+    display: inline-flex;
+    gap: calc(.25rem + var(--#{$prefix}nav-link-gap));
+    align-items: center;
+    margin: 0;
+    font-size: var(--#{$prefix}nav-font-size);
+    min-width: calc(var(--#{$prefix}nav-height) - 2 * var(--#{$prefix}nav-padding)); 
+    height: calc(var(--#{$prefix}nav-height) - 2 * var(--#{$prefix}nav-padding));
+    padding: 0 calc(var(--#{$prefix}nav-link-padding-x) - 2px);
+    border: 1px solid transparent;
+    background: transparent;
+    color: var(--#{$prefix}secondary);
+    text-align: center;
+    text-decoration: none;
+    white-space: nowrap;
+    cursor: pointer;
+    transition: background-color $transition-time, color $transition-time;
+    border-radius: var(--#{$prefix}nav-radius);
+    flex-grow: 1;   
+    justify-content: center;
+
+    &:hover,
+    &.hover  {
+      background: rgba(0, 0, 0, .04);
+      color: var(--#{$prefix}body-color);
+    }
+
+    &.disabled,
+    &:disabled {
+      color: var(--#{$prefix}nav-link-disabled-color);
+      cursor: not-allowed;
+    }
+  }
+
+  .nav-link-input:checked + .nav-link,
+  .nav-link.active {
+    color: var(--#{$prefix}body-color);
+    background: var(--#{$prefix}nav-active-bg);
+    border-color: var(--#{$prefix}border-color);
+  }
+
+  .nav-link-input {
+    display: none;
+  }
+
+  .nav-link-icon {
+    width: var(--#{$prefix}nav-link-icon-size);
+    height: var(--#{$prefix}nav-link-icon-size);
+    margin: 0 -.25rem;
+    color: inherit;
+  }
+}
+
+.nav-segmented-vertical {
+  flex-direction: column;
+
+  .nav-link {
+    justify-content: flex-start;
+  }
+}
+
+.nav-sm {
+  --#{$prefix}nav-height: 2rem;
+  --#{$prefix}nav-font-size: var(--tblr-font-size-h5);
+  --#{$prefix}nav-radius: 4px;
+  --#{$prefix}nav-link-padding-x: .5rem;
+  --#{$prefix}nav-link-gap: .25rem;
+  --#{$prefix}nav-link-icon-size: 1rem;
+}
+
+.nav-lg {
+  --#{$prefix}nav-height: 3rem;
+  --#{$prefix}nav-font-size: var(--tblr-font-size-h3);
+  --#{$prefix}nav-radius: 8px;
+  --#{$prefix}nav-link-padding-x: 1rem;
+  --#{$prefix}nav-link-gap: .5rem;
+  --#{$prefix}nav-link-icon-size: 1.5rem;
+}

+ 13 - 2
preview/eleventy.config.mjs

@@ -50,8 +50,8 @@ export default function (eleventyConfig) {
 	eleventyConfig.setLayoutsDirectory("_layouts");
 	eleventyConfig.setIncludesDirectory("_includes");
 
-	eleventyConfig.addWatchTarget("../core/dist/**");
-	eleventyConfig.setWatchThrottleWaitTime(100);
+	// eleventyConfig.addWatchTarget("../core/dist/**");
+	// eleventyConfig.setWatchThrottleWaitTime(100);
 
 	eleventyConfig.addPassthroughCopy(getCopyList());
 	eleventyConfig.setServerPassthroughCopyBehavior("passthrough");
@@ -66,6 +66,13 @@ export default function (eleventyConfig) {
 		dynamicPartials: true,
 		jekyllWhere: true,
 	});
+	/**
+	 * Server
+	 */
+	if (process.env.ELEVENTY_RUN_MODE === "serve") {
+		eleventyConfig.setServerPassthroughCopyBehavior("passthrough");
+	}
+
 
 	/**
 	 * Data
@@ -422,6 +429,10 @@ export default function (eleventyConfig) {
 		}
 	});
 
+	eleventyConfig.addFilter("contains", (items, item) => {
+		return items && Array.isArray(items) && items.includes(item);
+	});
+
 	eleventyConfig.addFilter("concat_objects", function (object, object2) {
 		if (
 			object &&

+ 1 - 1
preview/package.json

@@ -29,10 +29,10 @@
     "zip": "mkdir -p packages-zip && zip -r packages-zip/tabler-$(node -p \"require('./package.json').version\").zip demo/*"
   },
   "dependencies": {
+    "@tabler/core": "workspace:*",
     "@tabler/icons": "^3.29.0",
     "@melloware/coloris": "^0.19.1",
     "apexcharts": "^4.4.0",
-    "@tabler/core": "workspace:*",
     "star-rating.js": "^4.3.1",
     "tinymce": "^7.6.0",
     "tom-select": "^2.4.1",

+ 5 - 0
preview/pages/_data/menu.json

@@ -193,6 +193,11 @@
         "url": "placeholder.html",
         "title": "Placeholder"
       },
+      "segmented-control": {
+        "title": "Segmented control",
+        "url": "segmented-control.html",
+        "badge": "New"
+      },
       "social": {
         "title": "Social icons",
         "url": "social-icons.html"

+ 3 - 3
preview/pages/_includes/layout/page-header.html

@@ -3,7 +3,7 @@
 {% assign actions = page-header-actions | default: layout.page-header-actions %}
 {% assign pretitle = page-header-pretitle | default: layout.page-header-pretitle %}
 {% assign class = page-header-class | default: layout.page-header-class %}
-{% assign icon = page-header-icon | default: layout.page-header-icon %}
+{% assign page-icon = page-header-icon | default: layout.page-header-icon %}
 
 {% if page-header-file %}
 	{% include "layout/headers/{{ page-header-file }}.html" %}
@@ -20,8 +20,8 @@
 				</div>
 				{% endif %}
 				<h2 class="page-title">
-					{% if icon %}
-						{% include "ui/icon.html" icon=icon %}
+					{% if page-icon %}
+						{% include "ui/icon.html" icon=page-icon %}
 					{% endif %}
 					{{ page-header }}
 				</h2>

+ 1 - 1
preview/pages/_includes/ui/icon.html

@@ -23,7 +23,7 @@
 
 {% if site.useIconfont %}
 	<i class="icon ti ti-{{ icon-name }}{% if include.color %} {{ include.color }}{% endif %}{% if include.class %} {{ include.class }}{% endif %}"></i>
-{% else %}
+{% elsif icons[icon-name] %}
 	<!-- Download SVG icon from http://tabler.io/icons/icon/{{ icon-name }} -->
 	{% assign svg-icon = icons[icon-name].svg[icon-type] | default: '' %}
 	{% assign svg-icon = svg-icon | replace: '<path stroke="none" d="M0 0h24v24H0z" fill="none"/>', '' %}

+ 28 - 0
preview/pages/_includes/ui/nav-segmented.html

@@ -0,0 +1,28 @@
+{% assign segmented-items = include.items | default: "" | split: "," %}
+{% assign segmented-icons = include.icons | default: "" | split: "," %}
+{% assign segmented-disabled = include.disabled | default: "" | split: "," %}
+{% assign segmented-hover = include.hover | default: "" %}
+
+{% assign segmented-items-count = segmented-items | size %}
+{% assign segmented-icons-count = segmented-icons | size %}
+{% assign segmented-all-count = segmented-items-count %}
+
+{% if segmented-icons-count > segmented-all-count %}{% assign segmented-all-count = segmented-icons-count %}{% endif %}
+
+<nav class="nav nav-segmented{% if include.vertical %} nav-segmented-vertical{% endif %}{% if include.size %} nav-{{ include.size }}{% endif %}{% if include.full-width %} w-100{% endif %}{% if include.class %} {{ include.class }}{% endif %}" role="tablist">
+	{% for i in (1..segmented-all-count) %}
+		{% assign index = forloop.index | append: "" %}
+		{% assign disabled = segmented-disabled | contains: index %}
+
+		{% if include.name %}<input type="radio" class="nav-link-input" name="segmented" id="segmented-{{include.name }}-{{ index }}" {% if forloop.index == 1 %}checked{% endif %} />{% endif %}
+
+		<{% if include.name %}label for="segmented-{{include.name }}-{{ index }}"{% else %}button{% endif %} class="nav-link{% if forloop.index == 1 %}{% unless include.name %} active{% endunless %}{% endif %}{% if disabled %} disabled{% endif %}{% if segmented-hover == index %} hover{% endif %}" role="tab"{% unless include.name %} data-bs-toggle="tab"{% endunless %} aria-selected="{% if forloop.index == 1 %}true{% else %}false{% endif %}" {% if disabled %} aria-disabled="true"{% endif %}{% if forloop.index == 1 %} aria-current="page"{% endif %}>
+			{% if segmented-icons[forloop.index0] %}
+				{% include "ui/icon.html" icon=segmented-icons[forloop.index0] class="nav-link-icon" %}
+			{% endif %}
+			{% if segmented-items[forloop.index0] %}
+				{{ segmented-items[forloop.index0] }}
+			{% endif %}
+		</{% if include.name %}label{% else %}button{% endif %}>
+	{% endfor %}
+</nav>

+ 8 - 8
preview/pages/_includes/ui/trending.html

@@ -1,15 +1,15 @@
 {% assign value = include.value | default: 25 %}
 {% if value > 0 %}
-   {% assign color = 'green' %}
-   {% assign icon = 'trending-up' %}
+   {% assign trending-color = 'green' %}
+   {% assign trending-icon = 'trending-up' %}
 {% elsif value == 0 %}
-   {% assign color = 'yellow' %}
-   {% assign icon = 'minus' %}
+   {% assign trending-color = 'yellow' %}
+   {% assign trending-icon = 'minus' %}
 {% else %}
-   {% assign color = 'red' %}
-   {% assign icon = 'trending-down' %}
+   {% assign trending-color = 'red' %}
+   {% assign trending-icon = 'trending-down' %}
 {% endif %}
 
-<span class="text-{{ color }} d-inline-flex align-items-center lh-1{% if include.class %} {{ include.class }}{% endif %}">
-   {{ value }}% {% include "ui/icon.html" icon=icon class="ms-1" %}
+<span class="text-{{ trending-color }} d-inline-flex align-items-center lh-1{% if include.class %} {{ include.class }}{% endif %}">
+   {{ value }}% {% include "ui/icon.html" icon=trending-icon class="ms-1" %}
 </span>

+ 1 - 1
preview/pages/chat.html

@@ -1,5 +1,5 @@
 ---
-title: Playground
+title: Chat
 page-header: Chat
 page-menu: extra.chat
 layout: default

+ 0 - 153
preview/pages/playground.html

@@ -1,153 +0,0 @@
----
-layout: default
-permalink: playground.html 
----
-
-<div class="container-xl">
-      <div class="page-header d-print-none mb-4">
-        <div class="row align-items-center">
-          <div class="col">
-            <div class="page-pretitle"></div>
-            <div class="d-flex align-items-center">
-              <img
-                src="https://hebbkx1anhila5yf.public.blob.vercel-storage.com/chips-b5dF2YPuqsOD3mhXWZ7cLs6YW8B5QM.png"
-                alt="Tabler Logo"
-                class="h-8 me-2" 
-              />
-              <h2 class="page-title">tabler</h2>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      <div class="row row-deck row-cards">
-        <div class="col-sm-6 col-lg-6">
-          <div class="card">
-            <div class="card-body">
-              <div class="d-flex align-items-center">
-                <div class="subheader">Sales</div>
-                <div class="ms-auto lh-1">
-                  <div class="text-success d-inline-flex align-items-center lh-1">
-                    1%{" "}
-                    <svg
-                      xmlns="http://www.w3.org/2000/svg"
-                      class="icon ms-1"
-                      width="24"
-                      height="24"
-                      viewBox="0 0 24 24"
-                      strokeWidth="2"
-                      stroke="currentColor"
-                      fill="none"
-                      strokeLinecap="round"
-                      strokeLinejoin="round"
-                    >
-                      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
-                      <path d="M3 17l6 -6l4 4l8 -8" />
-                      <path d="M14 7l7 0l0 7" />
-                    </svg>
-                  </div>
-                </div>
-              </div>
-              <div class="d-flex align-items-baseline">
-                <div class="h1 mb-0 me-2">132</div>
-                <div class="me-auto">
-                  <span class="text-muted">12 waiting payments</span>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-        <div class="col-sm-6 col-lg-6">
-          <div class="card">
-            <div class="card-body">
-              <div class="d-flex align-items-center">
-                <div class="subheader">Orders</div>
-                <div class="ms-auto lh-1">
-                  <div class="text-muted d-inline-flex align-items-center lh-1">
-                    0% <span class="ms-1">─</span>
-                  </div>
-                </div>
-              </div>
-              <div class="d-flex align-items-baseline">
-                <div class="h1 mb-0 me-2">78</div>
-                <div class="me-auto">
-                  <span class="text-muted">32 shipped</span>
-                </div>
-              </div>
-            </div> 
-          </div>
-        </div>
-        <div class="col-sm-6 col-lg-6">
-          <div class="card">
-            <div class="card-body">
-              <div class="d-flex align-items-center">
-                <div class="subheader">Shares</div>
-                <div class="ms-auto lh-1">
-                  <div class="text-danger d-inline-flex align-items-center lh-1">
-                    4%{" "}
-                    <svg
-                      xmlns="http://www.w3.org/2000/svg"
-                      class="icon ms-1"
-                      width="24"
-                      height="24"
-                      viewBox="0 0 24 24"
-                      strokeWidth="2"
-                      stroke="currentColor"
-                      fill="none"
-                      strokeLinecap="round"
-                      strokeLinejoin="round"
-                    >
-                      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
-                      <path d="M3 7l6 6l4 -4l8 8" />
-                      <path d="M14 17l7 0l0 -7" />
-                    </svg>
-                  </div>
-                </div>
-              </div>
-              <div class="d-flex align-items-baseline">
-                <div class="h1 mb-0 me-2">623</div>
-                <div class="me-auto">
-                  <span class="text-muted">16 today</span>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-        <div class="col-sm-6 col-lg-6">
-          <div class="card">
-            <div class="card-body">
-              <div class="d-flex align-items-center">
-                <div class="subheader">Likes</div>
-                <div class="ms-auto lh-1">
-                  <div class="text-success d-inline-flex align-items-center lh-1">
-                    8%{" "}
-                    <svg
-                      xmlns="http://www.w3.org/2000/svg"
-                      class="icon ms-1"
-                      width="24"
-                      height="24"
-                      viewBox="0 0 24 24"
-                      strokeWidth="2"
-                      stroke="currentColor"
-                      fill="none"
-                      strokeLinecap="round"
-                      strokeLinejoin="round"
-                    >
-                      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
-                      <path d="M3 17l6 -6l4 4l8 -8" />
-                      <path d="M14 7l7 0l0 7" />
-                    </svg>
-                  </div>
-                </div>
-              </div>
-              <div class="d-flex align-items-baseline">
-                <div class="h1 mb-0 me-2">132</div>
-                <div class="me-auto">
-                  <span class="text-muted">21 today</span>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>

+ 109 - 0
preview/pages/segmented-control.html

@@ -0,0 +1,109 @@
+---
+layout: default
+title: Segmented control
+permalink: /segmented-control.html
+page-header: Segmented control
+page-menu: base.segmented-control
+---
+
+<div class="row row-cards">
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" items="1,2,3,4" %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" items="👦,👦🏿,👦🏾,👦🏽,👦🏼,👦🏻" %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" icons="home,star,clock,ghost,bold,italic,underline" %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" items="List,Kanban,Calendar,Files" icons="list,layout,calendar,files" %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" items="List,Kanban,Calendar,Files" icons="list,layout,calendar,files" vertical %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" icons="home,star,clock,ghost,bold,italic,underline" vertical disabled="3" %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" items="Daily,Weekly,Monthly,Quarterly,Yearly" disabled="4,5" %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" items="Daily,Weekly,Monthly,Quarterly,Yearly" vertical=true %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" items="Daily,Weekly,Monthly,Quarterly,Yearly" name="checkbox" %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				{% include "ui/nav-segmented.html" items="Daily,Weekly,Monthly,Quarterly,Yearly" full-width=true %}
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				<div class="space-y">
+					<div>{% include "ui/nav-segmented.html" items="Overview,Analytics,Reports,Notifications" full-width=true %}</div>
+					<div>{% include "ui/nav-segmented.html" items="Account,Password" full-width=true %}</div>
+				</div>
+			</div>
+		</div>
+	</div>
+	<div class="col-md-6">
+		<div class="card">
+			<div class="card-body">
+				<div class="space-y">
+					<div>{% include "ui/nav-segmented.html" items="List,Kanban,Calendar,Files" disabled="3,5" size="sm" %}</div>
+					<div>{% include "ui/nav-segmented.html" items="List,Kanban,Calendar,Files" disabled="3,5" %}</div>
+					<div>{% include "ui/nav-segmented.html" items="List,Kanban,Calendar,Files" disabled="3,5" size="lg" %}</div>
+
+					<div>{% include "ui/nav-segmented.html" items="List,Kanban,Calendar,Files" icons="list,layout,calendar,files" disabled="3,5" size="sm" %}</div>
+					<div>{% include "ui/nav-segmented.html" items="List,Kanban,Calendar,Files" icons="list,layout,calendar,files" disabled="3,5" %}</div>
+					<div>{% include "ui/nav-segmented.html" items="List,Kanban,Calendar,Files" icons="list,layout,calendar,files" disabled="3,5" size="lg" %}</div>
+					
+					<div>{% include "ui/nav-segmented.html" icons="list,layout,calendar,files" disabled="3,5" size="sm" %}</div>
+					<div>{% include "ui/nav-segmented.html" icons="list,layout,calendar,files" disabled="3,5" %}</div>
+					<div>{% include "ui/nav-segmented.html" icons="list,layout,calendar,files" disabled="3,5" size="lg" %}</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</div>