1656662400
Là nhà phát triển, chúng tôi thường cố gắng tối ưu hóa quy trình công việc của mình nhiều nhất có thể, tiết kiệm thời gian bằng cách tận dụng các công cụ như thiết bị đầu cuối. Bảng lệnh là một trong những công cụ hiển thị hoạt động gần đây trong ứng dụng web hoặc máy tính để bàn, cho phép điều hướng nhanh chóng, dễ dàng truy cập vào các lệnh và phím tắt, trong số những thứ khác.
Để nâng cao mức năng suất của bạn, bảng lệnh về cơ bản là một thành phần giao diện người dùng có dạng một phương thức. Ví dụ, một bảng lệnh đặc biệt hữu ích trong các ứng dụng lớn, phức tạp với nhiều bộ phận chuyển động, nơi bạn có thể mất vài lần nhấp chuột hoặc lướt qua nhiều menu thả xuống để truy cập tài nguyên.
Trong hướng dẫn này, chúng ta sẽ khám phá cách tạo một bảng lệnh đầy đủ chức năng từ đầu bằng cách sử dụng thành phần Headless UI Combobox và Tailwind CSS.
Là một nhà phát triển, có khả năng rất cao là bạn đã sử dụng bảng lệnh trước đó. Phổ biến nhất là bảng lệnh VS Code , nhưng có nhiều ví dụ khác, bao gồm Bảng lệnh GitHub, Linear, Figma, Slack, Monkeytype , v.v.
GitHub gần đây đã phát hành một tính năng bảng lệnh vẫn đang trong giai đoạn thử nghiệm công khai tại thời điểm viết bài. Nó cho phép bạn nhanh chóng chuyển đến các trang khác nhau, tìm kiếm lệnh và nhận đề xuất dựa trên ngữ cảnh hiện tại của bạn. Bạn cũng có thể thu hẹp phạm vi tài nguyên bạn đang tìm kiếm bằng cách chuyển sang một trong các tùy chọn hoặc sử dụng một ký tự đặc biệt:
Nếu bạn không quen thuộc với Linear , thì đó là một công cụ quản lý dự án tương tự như Jira và Asana mang lại trải nghiệm người dùng thực sự tuyệt vời. Linear có một bảng lệnh rất trực quan cho phép bạn truy cập toàn bộ chức năng của ứng dụng với thiết kế ưu tiên bàn phím. Trong hướng dẫn này, chúng tôi sẽ xây dựng một bảng lệnh tương tự như Linear:
Một số ứng dụng hiện đại đang triển khai bảng lệnh như một tính năng, nhưng điều gì tạo nên một thành phần bảng lệnh tốt? Dưới đây là danh sách ngắn gọn những điều cần chú ý:
ctrl + k
Trong phần tiếp theo, chúng tôi sẽ xây dựng thành phần của riêng mình bao gồm tất cả các tính năng được liệt kê ở trên. Hãy vào đó!
Bảng lệnh thực ra không quá phức tạp và bất kỳ ai cũng có thể tạo một bảng lệnh một cách nhanh chóng. Tôi đã chuẩn bị một dự án bắt đầu cho hướng dẫn này để bạn có thể dễ dàng làm theo. Dự án khởi động là một React và Vite SPA sao chép trang Các vấn đề tuyến tính.
Để bắt đầu, hãy sao chép kho lưu trữ vào thư mục cục bộ của bạn, cài đặt các phụ thuộc cần thiết và khởi động máy chủ phát triển. Dự án sử dụng Yarn, nhưng nếu bạn cảm thấy thoải mái hơn với npm hoặc pnPm, bạn có thể xóa yarn.lock
tệp trước khi chạy npm install
hoặc pnpm install
:
// clone repository
$ git clone https://github.com/Mayowa-Ojo/command-palette
// switch to the 'starter-project' branch
$ git checkout starter-project
// install dependencies
$ yarn
// start dev server
$ yarn dev
Nếu bạn truy cập localhost:3000
, bạn sẽ thấy trang sau:
CommandPalette
phầnTiếp theo, chúng ta sẽ xây dựng thành phần. Chúng tôi sẽ sử dụng giao diện người dùng Headless combobox
và dialog
các thành phần. combobox
sẽ là thành phần cơ sở cho bảng lệnh của chúng ta. Nó có các tính năng tích hợp như quản lý tiêu điểm và tương tác bàn phím. Chúng tôi sẽ sử dụng dialog
thành phần để hiển thị bảng lệnh của chúng tôi theo một phương thức.
Để tạo kiểu cho các thành phần, chúng tôi sẽ sử dụng Tailwind CSS. Tailwind là một thư viện tiện ích CSS cho phép bạn dễ dàng thêm các kiểu nội tuyến trong các tệp HTML hoặc JSX của mình. Dự án khởi động đã bao gồm cấu hình cho Tailwind.
Cài đặt các phụ thuộc cần thiết như sau:
$ yarn add @headlessui/react @heroicons/react
Trong components
thư mục, hãy tạo một CommandPalette.jsx
tệp và thêm khối mã sau:
import { Dialog, Combobox } from "@headlessui/react";
export const CommandPalette = ({ commands }) => {
const [isOpen, setIsOpen] = useState(true);
return (
<Dialog
open={isOpen}
onClose={setIsOpen}
className="fixed inset-0 p-4 pt-[15vh] overflow-y-auto"
>
<Dialog.Overlay className="fixed inset-0 backdrop-blur-[1px]" />
<Combobox
as="div"
className="bg-accent-dark max-w-2xl mx-auto rounded-lg shadow-2xl relative flex flex-col"
onChange={(command) => {
// we have access to the selected command
// a redirect can happen here or any action can be executed
setIsOpen(false);
}}
>
<div className="mx-4 mt-4 px-2 h-[25px] text-xs text-slate-100 bg-primary/30 rounded self-start flex items-center flex-shrink-0">
Issue
</div>
<div className="flex items-center text-lg font-medium border-b border-slate-500">
<Combobox.Input
className="p-5 text-white placeholder-gray-200 w-full bg-transparent border-0 outline-none"
placeholder="Type a command or search..."
/>
</div>
<Combobox.Options
className="max-h-72 overflow-y-auto flex flex-col"
static
></Combobox.Options>
</Combobox>
</Dialog>
);
};
Một vài điều đang xảy ra ở đây. Đầu tiên, chúng tôi nhập khẩu Dialog
và Combobox
các thành phần. Dialog
được hiển thị như một trình bao bọc xung quanh Combobox
và chúng tôi khởi tạo một trạng thái cục bộ được gọi isOpen
để điều khiển phương thức.
Chúng tôi kết xuất một Dialog.Overlay
bên trong Dialog
thành phần để phục vụ như lớp phủ cho phương thức. Bạn có thể tạo kiểu này theo cách bạn muốn, nhưng ở đây, chúng tôi chỉ đang sử dụng backdrop-blur
. Sau đó, chúng tôi kết xuất Combobox
thành phần và chuyển một hàm xử lý cho phần onChange
mềm hỗ trợ. Trình xử lý này được gọi bất cứ khi nào một mục được chọn trong Combobox
. Bạn thường muốn điều hướng đến một trang hoặc thực hiện một hành động ở đây, nhưng hiện tại, chúng tôi chỉ đóng Dialog
.
Combobox.Input
sẽ xử lý chức năng tìm kiếm mà chúng tôi sẽ bổ sung sau trong phần này. Combobox.Options
hiển thị một ul
phần tử bao bọc danh sách kết quả mà chúng tôi sẽ hiển thị. Chúng tôi chuyển vào một static
chỗ dựa cho biết chúng tôi muốn bỏ qua trạng thái được quản lý nội bộ của thành phần.
Tiếp theo, chúng tôi kết xuất của chúng tôi CommandPalette
trong App.jsx
tệp:
const App = () => {
return (
<div className="flex w-full bg-primary h-screen max-h-screen min-h-screen overflow-hidden">
<Drawer teams={teams} />
<AllIssues issues={issues} />
<CommandPalette commands={commands}/>
</div>
);
};
Hãy nói về cách bảng lệnh của chúng ta sẽ hoạt động. Chúng tôi có một danh sách các lệnh được xác định trước trong data/seed.json
tệp. Các lệnh này sẽ được hiển thị trong bảng màu khi nó được mở ra và có thể được lọc dựa trên truy vấn tìm kiếm. Khá đơn giản, phải không?
CommandGroup
phầnCommandPalette
nhận được một chỗ commands
dựa, là danh sách các lệnh mà chúng tôi đã nhập từ đó seed.json
. Bây giờ, hãy tạo một CommandGroup.jsx
tệp trong components
thư mục và thêm mã sau:
// CommandGroup.jsx
import React from "react";
import clsx from "clsx";
import { Combobox } from "@headlessui/react";
import { PlusIcon, ArrowSmRightIcon } from "@heroicons/react/solid";
import {
CogIcon,
UserCircleIcon,
FastForwardIcon,
} from "@heroicons/react/outline";
import { ProjectIcon } from "../icons/ProjectIcon";
import { ViewsIcon } from "../icons/ViewsIcon";
import { TemplatesIcon } from "../icons/TemplatesIcon";
import { TeamIcon } from "../icons/TeamIcon";
export const CommandGroup = ({ commands, group }) => {
return (
<React.Fragment>
{/* only show the header when there are commands belonging to this group */}
{commands.filter((command) => command.group === group).length >= 1 && (
<div className="flex items-center h-6 flex-shrink-0 bg-accent/50">
<span className="text-xs text-slate-100 px-3.5">{group}</span>
</div>
)}
{commands
.filter((command) => command.group === group)
.map((command, idx) => (
<Combobox.Option key={idx} value={command}>
{({ active }) => (
<div
className={clsx(
"w-full h-[46px] text-white flex items-center hover:bg-primary/40 cursor-default transition-colors duration-100 ease-in",
active ? "bg-primary/40" : ""
)}
>
<div className="px-3.5 flex items-center w-full">
<div className="mr-3 flex items-center justify-center w-4">
{mapCommandGroupToIcon(
command.group.toLowerCase()
)}
</div>
<span className="text-sm text-left flex flex-auto">
{command.name}
</span>
<span className="text-[10px]">{command.shortcut}</span>
</div>
</div>
)}
</Combobox.Option>
))}
</React.Fragment>
);
};
Chúng tôi chỉ đơn giản sử dụng CommandGroup
thành phần để tránh một số mã lặp lại. Nếu bạn nhìn vào bảng lệnh Linear, bạn sẽ thấy rằng các lệnh được nhóm lại dựa trên ngữ cảnh. Để thực hiện điều này, chúng ta cần lọc ra các lệnh thuộc cùng một nhóm và lặp lại logic đó cho mỗi nhóm.
Thành CommandGroup
phần nhận được hai đạo cụ, commands
và group
. Chúng tôi sẽ lọc các lệnh dựa trên nhóm hiện tại và hiển thị chúng bằng cách sử dụng Combobox.Option
thành phần. Sử dụng các đạo cụ kết xuất, chúng tôi có thể lấy active
mục và tạo kiểu cho phù hợp, cho phép chúng tôi kết xuất CommandGroup
cho từng nhóm trong CommandPalette
khi vẫn giữ mã sạch.
Lưu ý rằng chúng ta có một mapCommandGroupToIcon
hàm ở đâu đó trong khối mã ở trên. Điều này là do mỗi nhóm có một biểu tượng khác nhau và chức năng này chỉ là một công cụ trợ giúp để hiển thị biểu tượng chính xác cho nhóm hiện tại. Bây giờ, hãy thêm hàm ngay bên dưới CommandGroup
thành phần trong cùng một tệp:
const mapCommandGroupToIcon = (group) => {
switch (group) {
case "issue":
return <PlusIcon className="w-4 h-4 text-white"/>;
case "project":
Bây giờ, chúng ta cần kết xuất CommandGroup
thành phần trong CommandPalette
.
Nhập thành phần như sau:
import { CommandGroup } from "./CommandGroup";
Kết xuất nó bên trong Combobox.Options
cho mỗi nhóm:
<Combobox.Options
className="max-h-72 overflow-y-auto flex flex-col"
static
>
<CommandGroup commands={commands} group="Issue"/>
<CommandGroup commands={commands} group="Project"/>
<CommandGroup commands={commands} group="Views"/>
<CommandGroup commands={commands} group="Team"/>
<CommandGroup commands={commands} group="Templates"/>
<CommandGroup commands={commands} group="Navigation"/>
<CommandGroup commands={commands} group="Settings"/>
<CommandGroup commands={commands} group="Account"/>
</Combobox.Options>
Bạn sẽ thấy danh sách các lệnh đang được hiển thị ngay bây giờ. Bước tiếp theo là kết nối chức năng tìm kiếm.
Tạo một biến trạng thái cục bộ trong CommandPalette.jsx
:
// CommandPalette.jsx
const [query, setQuery] = useState("");
Chuyển trình xử lý cập nhật trạng thái đến phần onChange
hỗ trợ Combobox.Input
. query
Sẽ được cập nhật với mọi ký tự bạn nhập vào ô nhập liệu :
<Combobox.Input
className="p-5 text-white placeholder-gray-200 w-full bg-transparent border-0 outline-none"
placeholder="Type a command or search..."
onChange={(e) => setQuery(e.target.value)}
/>
Một trong những đặc tính chính của một bảng lệnh tốt là chức năng tìm kiếm mở rộng. Chúng tôi chỉ có thể thực hiện một phép so sánh chuỗi đơn giản của truy vấn tìm kiếm với các lệnh, tuy nhiên điều đó sẽ không tính đến lỗi chính tả và ngữ cảnh. Một giải pháp tốt hơn nhiều mà không giới thiệu quá nhiều phức tạp là tìm kiếm mờ.
Chúng tôi sẽ sử dụng thư viện Fuse.js cho việc này. Fuse.js là một thư viện tìm kiếm mờ, nhẹ, mạnh mẽ và không có phụ thuộc. Nếu bạn không quen với tìm kiếm mờ, thì đó là một kỹ thuật đối sánh chuỗi ủng hộ đối sánh gần đúng hơn đối sánh chính xác, ngụ ý rằng bạn có thể nhận được đề xuất chính xác ngay cả khi truy vấn có lỗi chính tả hoặc lỗi chính tả.
Đầu tiên, hãy cài đặt thư viện Fuse.js:
$ yarn add fuse.js
Trong CommandPalette.jsx
, khởi tạo Fuse
lớp bằng danh sách các lệnh:
// CommandPalette.jsx
const fuse = new Fuse(commands, { includeScore: true, keys: ["name"] });
Lớp Fuse
chấp nhận một loạt các lệnh và các tùy chọn cấu hình. Trường keys
là nơi chúng ta đăng ký những trường nào trong danh sách lệnh sẽ được lập chỉ mục bởi Fuse.js. Bây giờ, hãy tạo một hàm sẽ xử lý tìm kiếm và trả về kết quả đã lọc:
// CommandPalette.jsx
const filteredCommands =
query === ""
? commands
: fuse.search(query).map((res) => ({ ...res.item }));
Chúng tôi kiểm tra xem query
có trống không, trả về tất cả các lệnh và nếu không, hãy chạy fuse.search
phương thức với truy vấn. Ngoài ra, chúng tôi đang ánh xạ các kết quả để tạo một đối tượng mới. Điều này là để duy trì tính nhất quán vì kết quả trả về bởi Fuse.js có một số trường mới và sẽ không khớp với cấu trúc mà chúng ta đã có.
Bây giờ, hãy chuyển filteredCommands
cho phần commands
hỗ trợ trong mỗi CommandGroup
thành phần. Nó sẽ giống như mã bên dưới:
// CommandPalette.jsx
<CommandGroup commands={filteredCommands} group="Issue"/>
<CommandGroup commands={filteredCommands} group="Project"/>
<CommandGroup commands={filteredCommands} group="Views"/>
<CommandGroup commands={filteredCommands} group="Team"/>
<CommandGroup commands={filteredCommands} group="Templates"/>
<CommandGroup commands={filteredCommands} group="Navigation"/>
<CommandGroup commands={filteredCommands} group="Settings"/>
<CommandGroup commands={filteredCommands} group="Account"/>
Hãy thử tìm kiếm trong bảng lệnh và xem kết quả có đang được lọc hay không:
Chúng tôi có một bảng lệnh đầy đủ chức năng, nhưng bạn có thể nhận thấy rằng nó luôn mở. Chúng ta cần có khả năng kiểm soát trạng thái mở của nó. Hãy xác định một sự kiện bàn phím sẽ lắng nghe tổ hợp phím và cập nhật trạng thái mở. Thêm mã sau vào CommandPalette.jsx
:
// CommandPalette.jsx
useEffect(() => {
const onKeydown = (e) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setIsOpen(true);
}
};
window.addEventListener("keydown", onKeydown);
return () => {
window.removeEventListener("keydown", onKeydown);
};
}, []);
Chúng tôi đang sử dụng useEffect
Hook để đăng ký keydown
sự kiện bàn phím khi thành phần được gắn kết và chúng tôi sử dụng chức năng dọn dẹp để xóa trình nghe khi thành phần ngắt kết nối.
Trong Hook, chúng tôi kiểm tra xem tổ hợp phím có khớp không ctrl + k
. Nếu có, thì trạng thái mở được đặt thành true
. Bạn cũng có thể sử dụng một tổ hợp phím khác, nhưng điều quan trọng là không sử dụng các tổ hợp xung đột với các phím tắt của trình duyệt gốc.
Đó là nó! Bạn có thể tìm thấy phiên bản hoàn chỉnh của dự án này trên nhánh dự án đã hoàn thành .
Chúng tôi đã khám phá cách xây dựng một thành phần bảng lệnh từ đầu. Tuy nhiên, có lẽ bạn không nên tự xây dựng mỗi khi bạn cần một bảng lệnh. Đó là nơi mà một thành phần dựng sẵn có thể hữu ích. Hầu hết các thư viện thành phần không cung cấp bảng lệnh, nhưng bảng phản ứng lệnh là một thành phần được viết tốt, có thể truy cập và tương thích với trình duyệt.
Để sử dụng thành phần này, hãy cài đặt nó làm thành phần phụ thuộc trong dự án của bạn:
$ yarn add react-command-palette
Nhập thành phần và chuyển danh sách lệnh của bạn cho nó như sau:
import React from "react";
import CommandPalette from 'react-command-palette';
const commands = [{
name: "Foo",
command() {}
},{
name: "Bar",
command() {}
}]
export default function App() {
return (
<div>
<CommandPalette commands={commands} />
</div>
);
}
Có rất nhiều tùy chọn cấu hình mà bạn có thể sử dụng để tùy chỉnh giao diện và hành vi đáp ứng yêu cầu của mình. Ví dụ: theme
cấu hình cho phép bạn chọn từ một số chủ đề tích hợp sẵn hoặc tạo chủ đề tùy chỉnh của riêng bạn.
Trong bài viết này, bạn đã tìm hiểu về các bảng lệnh, các trường hợp sử dụng lý tưởng cho chúng và những tính năng nào tạo nên một bảng lệnh tốt. Bạn cũng đã khám phá các bước chi tiết về cách tạo một công cụ bằng cách sử dụng thành phần hộp kết hợp Headless UI và Tailwind CSS.
Nếu bạn chỉ muốn nhanh chóng đưa tính năng này vào ứng dụng của mình, thì một thành phần được xây dựng sẵn như react-command-Palette là cách để thực hiện. Cảm ơn bạn đã đọc, và hãy để lại bình luận nếu bạn có bất kỳ câu hỏi nào.
Nguồn: https://blog.logrocket.com/react-command-palette-tailwind-css-headless-ui/
1627084440
Using Headless UI in React, we easily create a react ready listbox component and then incorporate the Headless UI Transition component as well.
Headless UI Documentation: https://github.com/tailwindlabs/headlessui/blob/develop/packages/%40headlessui-react/README.md
📚 Library(s) needed:
npm install tailwindcss
npm install @headlessui/react
🖥️ Source code: https://devascend.com/github?link=https://github.com/DevAscend/YT-HeadlessUI-React-Tutorials
💡 Have a video request?
Suggest it in the Dev Ascend Discord community server or leave it in the comments below!
🕐 Timestamps:
00:00 Introduction
00:34 Creating the Listbox component
05:45 Incorporating the Transition component
#headless #ui #react
#headless #ui #react #tailwind css #css
1656662400
Là nhà phát triển, chúng tôi thường cố gắng tối ưu hóa quy trình công việc của mình nhiều nhất có thể, tiết kiệm thời gian bằng cách tận dụng các công cụ như thiết bị đầu cuối. Bảng lệnh là một trong những công cụ hiển thị hoạt động gần đây trong ứng dụng web hoặc máy tính để bàn, cho phép điều hướng nhanh chóng, dễ dàng truy cập vào các lệnh và phím tắt, trong số những thứ khác.
Để nâng cao mức năng suất của bạn, bảng lệnh về cơ bản là một thành phần giao diện người dùng có dạng một phương thức. Ví dụ, một bảng lệnh đặc biệt hữu ích trong các ứng dụng lớn, phức tạp với nhiều bộ phận chuyển động, nơi bạn có thể mất vài lần nhấp chuột hoặc lướt qua nhiều menu thả xuống để truy cập tài nguyên.
Trong hướng dẫn này, chúng ta sẽ khám phá cách tạo một bảng lệnh đầy đủ chức năng từ đầu bằng cách sử dụng thành phần Headless UI Combobox và Tailwind CSS.
Là một nhà phát triển, có khả năng rất cao là bạn đã sử dụng bảng lệnh trước đó. Phổ biến nhất là bảng lệnh VS Code , nhưng có nhiều ví dụ khác, bao gồm Bảng lệnh GitHub, Linear, Figma, Slack, Monkeytype , v.v.
GitHub gần đây đã phát hành một tính năng bảng lệnh vẫn đang trong giai đoạn thử nghiệm công khai tại thời điểm viết bài. Nó cho phép bạn nhanh chóng chuyển đến các trang khác nhau, tìm kiếm lệnh và nhận đề xuất dựa trên ngữ cảnh hiện tại của bạn. Bạn cũng có thể thu hẹp phạm vi tài nguyên bạn đang tìm kiếm bằng cách chuyển sang một trong các tùy chọn hoặc sử dụng một ký tự đặc biệt:
Nếu bạn không quen thuộc với Linear , thì đó là một công cụ quản lý dự án tương tự như Jira và Asana mang lại trải nghiệm người dùng thực sự tuyệt vời. Linear có một bảng lệnh rất trực quan cho phép bạn truy cập toàn bộ chức năng của ứng dụng với thiết kế ưu tiên bàn phím. Trong hướng dẫn này, chúng tôi sẽ xây dựng một bảng lệnh tương tự như Linear:
Một số ứng dụng hiện đại đang triển khai bảng lệnh như một tính năng, nhưng điều gì tạo nên một thành phần bảng lệnh tốt? Dưới đây là danh sách ngắn gọn những điều cần chú ý:
ctrl + k
Trong phần tiếp theo, chúng tôi sẽ xây dựng thành phần của riêng mình bao gồm tất cả các tính năng được liệt kê ở trên. Hãy vào đó!
Bảng lệnh thực ra không quá phức tạp và bất kỳ ai cũng có thể tạo một bảng lệnh một cách nhanh chóng. Tôi đã chuẩn bị một dự án bắt đầu cho hướng dẫn này để bạn có thể dễ dàng làm theo. Dự án khởi động là một React và Vite SPA sao chép trang Các vấn đề tuyến tính.
Để bắt đầu, hãy sao chép kho lưu trữ vào thư mục cục bộ của bạn, cài đặt các phụ thuộc cần thiết và khởi động máy chủ phát triển. Dự án sử dụng Yarn, nhưng nếu bạn cảm thấy thoải mái hơn với npm hoặc pnPm, bạn có thể xóa yarn.lock
tệp trước khi chạy npm install
hoặc pnpm install
:
// clone repository
$ git clone https://github.com/Mayowa-Ojo/command-palette
// switch to the 'starter-project' branch
$ git checkout starter-project
// install dependencies
$ yarn
// start dev server
$ yarn dev
Nếu bạn truy cập localhost:3000
, bạn sẽ thấy trang sau:
CommandPalette
phầnTiếp theo, chúng ta sẽ xây dựng thành phần. Chúng tôi sẽ sử dụng giao diện người dùng Headless combobox
và dialog
các thành phần. combobox
sẽ là thành phần cơ sở cho bảng lệnh của chúng ta. Nó có các tính năng tích hợp như quản lý tiêu điểm và tương tác bàn phím. Chúng tôi sẽ sử dụng dialog
thành phần để hiển thị bảng lệnh của chúng tôi theo một phương thức.
Để tạo kiểu cho các thành phần, chúng tôi sẽ sử dụng Tailwind CSS. Tailwind là một thư viện tiện ích CSS cho phép bạn dễ dàng thêm các kiểu nội tuyến trong các tệp HTML hoặc JSX của mình. Dự án khởi động đã bao gồm cấu hình cho Tailwind.
Cài đặt các phụ thuộc cần thiết như sau:
$ yarn add @headlessui/react @heroicons/react
Trong components
thư mục, hãy tạo một CommandPalette.jsx
tệp và thêm khối mã sau:
import { Dialog, Combobox } from "@headlessui/react";
export const CommandPalette = ({ commands }) => {
const [isOpen, setIsOpen] = useState(true);
return (
<Dialog
open={isOpen}
onClose={setIsOpen}
className="fixed inset-0 p-4 pt-[15vh] overflow-y-auto"
>
<Dialog.Overlay className="fixed inset-0 backdrop-blur-[1px]" />
<Combobox
as="div"
className="bg-accent-dark max-w-2xl mx-auto rounded-lg shadow-2xl relative flex flex-col"
onChange={(command) => {
// we have access to the selected command
// a redirect can happen here or any action can be executed
setIsOpen(false);
}}
>
<div className="mx-4 mt-4 px-2 h-[25px] text-xs text-slate-100 bg-primary/30 rounded self-start flex items-center flex-shrink-0">
Issue
</div>
<div className="flex items-center text-lg font-medium border-b border-slate-500">
<Combobox.Input
className="p-5 text-white placeholder-gray-200 w-full bg-transparent border-0 outline-none"
placeholder="Type a command or search..."
/>
</div>
<Combobox.Options
className="max-h-72 overflow-y-auto flex flex-col"
static
></Combobox.Options>
</Combobox>
</Dialog>
);
};
Một vài điều đang xảy ra ở đây. Đầu tiên, chúng tôi nhập khẩu Dialog
và Combobox
các thành phần. Dialog
được hiển thị như một trình bao bọc xung quanh Combobox
và chúng tôi khởi tạo một trạng thái cục bộ được gọi isOpen
để điều khiển phương thức.
Chúng tôi kết xuất một Dialog.Overlay
bên trong Dialog
thành phần để phục vụ như lớp phủ cho phương thức. Bạn có thể tạo kiểu này theo cách bạn muốn, nhưng ở đây, chúng tôi chỉ đang sử dụng backdrop-blur
. Sau đó, chúng tôi kết xuất Combobox
thành phần và chuyển một hàm xử lý cho phần onChange
mềm hỗ trợ. Trình xử lý này được gọi bất cứ khi nào một mục được chọn trong Combobox
. Bạn thường muốn điều hướng đến một trang hoặc thực hiện một hành động ở đây, nhưng hiện tại, chúng tôi chỉ đóng Dialog
.
Combobox.Input
sẽ xử lý chức năng tìm kiếm mà chúng tôi sẽ bổ sung sau trong phần này. Combobox.Options
hiển thị một ul
phần tử bao bọc danh sách kết quả mà chúng tôi sẽ hiển thị. Chúng tôi chuyển vào một static
chỗ dựa cho biết chúng tôi muốn bỏ qua trạng thái được quản lý nội bộ của thành phần.
Tiếp theo, chúng tôi kết xuất của chúng tôi CommandPalette
trong App.jsx
tệp:
const App = () => {
return (
<div className="flex w-full bg-primary h-screen max-h-screen min-h-screen overflow-hidden">
<Drawer teams={teams} />
<AllIssues issues={issues} />
<CommandPalette commands={commands}/>
</div>
);
};
Hãy nói về cách bảng lệnh của chúng ta sẽ hoạt động. Chúng tôi có một danh sách các lệnh được xác định trước trong data/seed.json
tệp. Các lệnh này sẽ được hiển thị trong bảng màu khi nó được mở ra và có thể được lọc dựa trên truy vấn tìm kiếm. Khá đơn giản, phải không?
CommandGroup
phầnCommandPalette
nhận được một chỗ commands
dựa, là danh sách các lệnh mà chúng tôi đã nhập từ đó seed.json
. Bây giờ, hãy tạo một CommandGroup.jsx
tệp trong components
thư mục và thêm mã sau:
// CommandGroup.jsx
import React from "react";
import clsx from "clsx";
import { Combobox } from "@headlessui/react";
import { PlusIcon, ArrowSmRightIcon } from "@heroicons/react/solid";
import {
CogIcon,
UserCircleIcon,
FastForwardIcon,
} from "@heroicons/react/outline";
import { ProjectIcon } from "../icons/ProjectIcon";
import { ViewsIcon } from "../icons/ViewsIcon";
import { TemplatesIcon } from "../icons/TemplatesIcon";
import { TeamIcon } from "../icons/TeamIcon";
export const CommandGroup = ({ commands, group }) => {
return (
<React.Fragment>
{/* only show the header when there are commands belonging to this group */}
{commands.filter((command) => command.group === group).length >= 1 && (
<div className="flex items-center h-6 flex-shrink-0 bg-accent/50">
<span className="text-xs text-slate-100 px-3.5">{group}</span>
</div>
)}
{commands
.filter((command) => command.group === group)
.map((command, idx) => (
<Combobox.Option key={idx} value={command}>
{({ active }) => (
<div
className={clsx(
"w-full h-[46px] text-white flex items-center hover:bg-primary/40 cursor-default transition-colors duration-100 ease-in",
active ? "bg-primary/40" : ""
)}
>
<div className="px-3.5 flex items-center w-full">
<div className="mr-3 flex items-center justify-center w-4">
{mapCommandGroupToIcon(
command.group.toLowerCase()
)}
</div>
<span className="text-sm text-left flex flex-auto">
{command.name}
</span>
<span className="text-[10px]">{command.shortcut}</span>
</div>
</div>
)}
</Combobox.Option>
))}
</React.Fragment>
);
};
Chúng tôi chỉ đơn giản sử dụng CommandGroup
thành phần để tránh một số mã lặp lại. Nếu bạn nhìn vào bảng lệnh Linear, bạn sẽ thấy rằng các lệnh được nhóm lại dựa trên ngữ cảnh. Để thực hiện điều này, chúng ta cần lọc ra các lệnh thuộc cùng một nhóm và lặp lại logic đó cho mỗi nhóm.
Thành CommandGroup
phần nhận được hai đạo cụ, commands
và group
. Chúng tôi sẽ lọc các lệnh dựa trên nhóm hiện tại và hiển thị chúng bằng cách sử dụng Combobox.Option
thành phần. Sử dụng các đạo cụ kết xuất, chúng tôi có thể lấy active
mục và tạo kiểu cho phù hợp, cho phép chúng tôi kết xuất CommandGroup
cho từng nhóm trong CommandPalette
khi vẫn giữ mã sạch.
Lưu ý rằng chúng ta có một mapCommandGroupToIcon
hàm ở đâu đó trong khối mã ở trên. Điều này là do mỗi nhóm có một biểu tượng khác nhau và chức năng này chỉ là một công cụ trợ giúp để hiển thị biểu tượng chính xác cho nhóm hiện tại. Bây giờ, hãy thêm hàm ngay bên dưới CommandGroup
thành phần trong cùng một tệp:
const mapCommandGroupToIcon = (group) => {
switch (group) {
case "issue":
return <PlusIcon className="w-4 h-4 text-white"/>;
case "project":
Bây giờ, chúng ta cần kết xuất CommandGroup
thành phần trong CommandPalette
.
Nhập thành phần như sau:
import { CommandGroup } from "./CommandGroup";
Kết xuất nó bên trong Combobox.Options
cho mỗi nhóm:
<Combobox.Options
className="max-h-72 overflow-y-auto flex flex-col"
static
>
<CommandGroup commands={commands} group="Issue"/>
<CommandGroup commands={commands} group="Project"/>
<CommandGroup commands={commands} group="Views"/>
<CommandGroup commands={commands} group="Team"/>
<CommandGroup commands={commands} group="Templates"/>
<CommandGroup commands={commands} group="Navigation"/>
<CommandGroup commands={commands} group="Settings"/>
<CommandGroup commands={commands} group="Account"/>
</Combobox.Options>
Bạn sẽ thấy danh sách các lệnh đang được hiển thị ngay bây giờ. Bước tiếp theo là kết nối chức năng tìm kiếm.
Tạo một biến trạng thái cục bộ trong CommandPalette.jsx
:
// CommandPalette.jsx
const [query, setQuery] = useState("");
Chuyển trình xử lý cập nhật trạng thái đến phần onChange
hỗ trợ Combobox.Input
. query
Sẽ được cập nhật với mọi ký tự bạn nhập vào ô nhập liệu :
<Combobox.Input
className="p-5 text-white placeholder-gray-200 w-full bg-transparent border-0 outline-none"
placeholder="Type a command or search..."
onChange={(e) => setQuery(e.target.value)}
/>
Một trong những đặc tính chính của một bảng lệnh tốt là chức năng tìm kiếm mở rộng. Chúng tôi chỉ có thể thực hiện một phép so sánh chuỗi đơn giản của truy vấn tìm kiếm với các lệnh, tuy nhiên điều đó sẽ không tính đến lỗi chính tả và ngữ cảnh. Một giải pháp tốt hơn nhiều mà không giới thiệu quá nhiều phức tạp là tìm kiếm mờ.
Chúng tôi sẽ sử dụng thư viện Fuse.js cho việc này. Fuse.js là một thư viện tìm kiếm mờ, nhẹ, mạnh mẽ và không có phụ thuộc. Nếu bạn không quen với tìm kiếm mờ, thì đó là một kỹ thuật đối sánh chuỗi ủng hộ đối sánh gần đúng hơn đối sánh chính xác, ngụ ý rằng bạn có thể nhận được đề xuất chính xác ngay cả khi truy vấn có lỗi chính tả hoặc lỗi chính tả.
Đầu tiên, hãy cài đặt thư viện Fuse.js:
$ yarn add fuse.js
Trong CommandPalette.jsx
, khởi tạo Fuse
lớp bằng danh sách các lệnh:
// CommandPalette.jsx
const fuse = new Fuse(commands, { includeScore: true, keys: ["name"] });
Lớp Fuse
chấp nhận một loạt các lệnh và các tùy chọn cấu hình. Trường keys
là nơi chúng ta đăng ký những trường nào trong danh sách lệnh sẽ được lập chỉ mục bởi Fuse.js. Bây giờ, hãy tạo một hàm sẽ xử lý tìm kiếm và trả về kết quả đã lọc:
// CommandPalette.jsx
const filteredCommands =
query === ""
? commands
: fuse.search(query).map((res) => ({ ...res.item }));
Chúng tôi kiểm tra xem query
có trống không, trả về tất cả các lệnh và nếu không, hãy chạy fuse.search
phương thức với truy vấn. Ngoài ra, chúng tôi đang ánh xạ các kết quả để tạo một đối tượng mới. Điều này là để duy trì tính nhất quán vì kết quả trả về bởi Fuse.js có một số trường mới và sẽ không khớp với cấu trúc mà chúng ta đã có.
Bây giờ, hãy chuyển filteredCommands
cho phần commands
hỗ trợ trong mỗi CommandGroup
thành phần. Nó sẽ giống như mã bên dưới:
// CommandPalette.jsx
<CommandGroup commands={filteredCommands} group="Issue"/>
<CommandGroup commands={filteredCommands} group="Project"/>
<CommandGroup commands={filteredCommands} group="Views"/>
<CommandGroup commands={filteredCommands} group="Team"/>
<CommandGroup commands={filteredCommands} group="Templates"/>
<CommandGroup commands={filteredCommands} group="Navigation"/>
<CommandGroup commands={filteredCommands} group="Settings"/>
<CommandGroup commands={filteredCommands} group="Account"/>
Hãy thử tìm kiếm trong bảng lệnh và xem kết quả có đang được lọc hay không:
Chúng tôi có một bảng lệnh đầy đủ chức năng, nhưng bạn có thể nhận thấy rằng nó luôn mở. Chúng ta cần có khả năng kiểm soát trạng thái mở của nó. Hãy xác định một sự kiện bàn phím sẽ lắng nghe tổ hợp phím và cập nhật trạng thái mở. Thêm mã sau vào CommandPalette.jsx
:
// CommandPalette.jsx
useEffect(() => {
const onKeydown = (e) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setIsOpen(true);
}
};
window.addEventListener("keydown", onKeydown);
return () => {
window.removeEventListener("keydown", onKeydown);
};
}, []);
Chúng tôi đang sử dụng useEffect
Hook để đăng ký keydown
sự kiện bàn phím khi thành phần được gắn kết và chúng tôi sử dụng chức năng dọn dẹp để xóa trình nghe khi thành phần ngắt kết nối.
Trong Hook, chúng tôi kiểm tra xem tổ hợp phím có khớp không ctrl + k
. Nếu có, thì trạng thái mở được đặt thành true
. Bạn cũng có thể sử dụng một tổ hợp phím khác, nhưng điều quan trọng là không sử dụng các tổ hợp xung đột với các phím tắt của trình duyệt gốc.
Đó là nó! Bạn có thể tìm thấy phiên bản hoàn chỉnh của dự án này trên nhánh dự án đã hoàn thành .
Chúng tôi đã khám phá cách xây dựng một thành phần bảng lệnh từ đầu. Tuy nhiên, có lẽ bạn không nên tự xây dựng mỗi khi bạn cần một bảng lệnh. Đó là nơi mà một thành phần dựng sẵn có thể hữu ích. Hầu hết các thư viện thành phần không cung cấp bảng lệnh, nhưng bảng phản ứng lệnh là một thành phần được viết tốt, có thể truy cập và tương thích với trình duyệt.
Để sử dụng thành phần này, hãy cài đặt nó làm thành phần phụ thuộc trong dự án của bạn:
$ yarn add react-command-palette
Nhập thành phần và chuyển danh sách lệnh của bạn cho nó như sau:
import React from "react";
import CommandPalette from 'react-command-palette';
const commands = [{
name: "Foo",
command() {}
},{
name: "Bar",
command() {}
}]
export default function App() {
return (
<div>
<CommandPalette commands={commands} />
</div>
);
}
Có rất nhiều tùy chọn cấu hình mà bạn có thể sử dụng để tùy chỉnh giao diện và hành vi đáp ứng yêu cầu của mình. Ví dụ: theme
cấu hình cho phép bạn chọn từ một số chủ đề tích hợp sẵn hoặc tạo chủ đề tùy chỉnh của riêng bạn.
Trong bài viết này, bạn đã tìm hiểu về các bảng lệnh, các trường hợp sử dụng lý tưởng cho chúng và những tính năng nào tạo nên một bảng lệnh tốt. Bạn cũng đã khám phá các bước chi tiết về cách tạo một công cụ bằng cách sử dụng thành phần hộp kết hợp Headless UI và Tailwind CSS.
Nếu bạn chỉ muốn nhanh chóng đưa tính năng này vào ứng dụng của mình, thì một thành phần được xây dựng sẵn như react-command-Palette là cách để thực hiện. Cảm ơn bạn đã đọc, và hãy để lại bình luận nếu bạn có bất kỳ câu hỏi nào.
Nguồn: https://blog.logrocket.com/react-command-palette-tailwind-css-headless-ui/
1626053833
Check out the course article and get the github repo here:
Learning Resources:
https://www.w3schools.com/css/css_rwd_mediaqueries.asp
https://tailwindcss.com/docs/breakpoints
https://material-ui.com/customization/breakpoints/#custom-breakpoints
Social Media:
https://twitter.com/LevelUpDev1
https://www.instagram.com/levelupdeveloper
#tailwindcss #materialui #css
#css #breakpoints #tailwind #material ui #css
1617809880
Let’s talk Tailwind.css. It’s new, it’s customizable, it’s responsive, and a utility-first CSS framework, let’s try it out!
The beauty of Tailwind.css is that to use it is pretty simple. In good old basic CSS, you will declare classes and specifically code the design elements that will come from the class you’ve created(i.e. Font-family, color). In Tailwind, you also use class names, but different from classic CSS, you pull from a pre-created library of class names that you will have access to once you download Tailwind into your app. It’s a matter of understanding what class names you’ll need, and that is going to take a little searching on the Tailwind Docs Website search bar. Nothing like a handy search!
#tailwind-ui #css #web-development #tailwind-css
1596530868
Want to develop a website or re-design using CSS Development?
We build a website and we implemented CSS successfully if you are planning to Hire CSS Developer from HourlyDeveloper.io, We can fill your Page with creative colors and attractive Designs. We provide services in Web Designing, Website Redesigning and etc.
For more details…!!
Consult with our experts:- https://bit.ly/3hUdppS
#hire css developer #css development company #css development services #css development #css developer #css