mirror of
				https://github.com/nonebot/nonebot2.git
				synced 2025-11-04 00:46:43 +00:00 
			
		
		
		
	📝 Docs: 升级新版 NonePress 主题 (#2375)
This commit is contained in:
		
							
								
								
									
										118
									
								
								website/src/components/Searcher/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								website/src/components/Searcher/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
import React, { useRef } from "react";
 | 
			
		||||
 | 
			
		||||
import clsx from "clsx";
 | 
			
		||||
 | 
			
		||||
import "./styles.css";
 | 
			
		||||
import { translate } from "@docusaurus/Translate";
 | 
			
		||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 | 
			
		||||
 | 
			
		||||
export type Props = {
 | 
			
		||||
  onChange: (value: string) => void;
 | 
			
		||||
  onSubmit: (value: string) => void;
 | 
			
		||||
  onBackspace: () => void;
 | 
			
		||||
  onClear: () => void;
 | 
			
		||||
  onTagClick: (index: number) => void;
 | 
			
		||||
  tags?: string[];
 | 
			
		||||
  className?: string;
 | 
			
		||||
  placeholder?: string;
 | 
			
		||||
  disabled?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function Searcher({
 | 
			
		||||
  onChange,
 | 
			
		||||
  onSubmit,
 | 
			
		||||
  onBackspace,
 | 
			
		||||
  onClear,
 | 
			
		||||
  onTagClick,
 | 
			
		||||
  tags = [],
 | 
			
		||||
  className,
 | 
			
		||||
  placeholder,
 | 
			
		||||
  disabled = false,
 | 
			
		||||
}: Props): JSX.Element {
 | 
			
		||||
  const ref = useRef<HTMLInputElement>(null);
 | 
			
		||||
 | 
			
		||||
  const handleSubmit = (e: React.FormEvent<HTMLInputElement>) => {
 | 
			
		||||
    onSubmit(e.currentTarget.value);
 | 
			
		||||
    e.currentTarget.value = "";
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleEscape = (e: React.KeyboardEvent<HTMLInputElement>) => {
 | 
			
		||||
    e.currentTarget.value = "";
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleBackspace = (e: React.KeyboardEvent<HTMLInputElement>) => {
 | 
			
		||||
    if (e.currentTarget.value === "") {
 | 
			
		||||
      onBackspace();
 | 
			
		||||
      e.preventDefault();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
 | 
			
		||||
    switch (e.key) {
 | 
			
		||||
      case "Enter": {
 | 
			
		||||
        handleSubmit(e);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case "Escape": {
 | 
			
		||||
        handleEscape(e);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case "Backspace": {
 | 
			
		||||
        handleBackspace(e);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleClear = () => {
 | 
			
		||||
    if (ref.current) {
 | 
			
		||||
      ref.current.value = "";
 | 
			
		||||
      ref.current.focus();
 | 
			
		||||
    }
 | 
			
		||||
    onClear();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={clsx("searcher-box", className)}>
 | 
			
		||||
      <div className="searcher-container">
 | 
			
		||||
        {tags.map((tag, index) => (
 | 
			
		||||
          <div
 | 
			
		||||
            key={index}
 | 
			
		||||
            className="badge badge-primary searcher-tag"
 | 
			
		||||
            onClick={() => onTagClick(index)}
 | 
			
		||||
          >
 | 
			
		||||
            {tag}
 | 
			
		||||
          </div>
 | 
			
		||||
        ))}
 | 
			
		||||
        <input
 | 
			
		||||
          ref={ref}
 | 
			
		||||
          className="searcher-input"
 | 
			
		||||
          placeholder={
 | 
			
		||||
            placeholder ??
 | 
			
		||||
            translate({
 | 
			
		||||
              id: "theme.searcher.input.placeholder",
 | 
			
		||||
              description: "Search input placeholder",
 | 
			
		||||
              message: "搜索",
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
          onChange={(e) => onChange(e.currentTarget.value)}
 | 
			
		||||
          onKeyDown={handleKeyDown}
 | 
			
		||||
          disabled={disabled}
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div className="searcher-action" onClick={handleClear}>
 | 
			
		||||
        <FontAwesomeIcon
 | 
			
		||||
          className="searcher-action-icon search"
 | 
			
		||||
          icon={["fas", "magnifying-glass"]}
 | 
			
		||||
        />
 | 
			
		||||
        <FontAwesomeIcon
 | 
			
		||||
          className="searcher-action-icon close"
 | 
			
		||||
          icon={["fas", "xmark"]}
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								website/src/components/Searcher/styles.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								website/src/components/Searcher/styles.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
.searcher {
 | 
			
		||||
  &-box {
 | 
			
		||||
    @apply flex items-center w-full rounded-3xl bg-base-200;
 | 
			
		||||
    @apply transition-[color,background-color] duration-500;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-container {
 | 
			
		||||
    @apply flex-1 flex items-center flex-wrap gap-x-1 gap-y-2;
 | 
			
		||||
    @apply pl-5 py-3;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-tag {
 | 
			
		||||
    @apply flex-initial shrink-0;
 | 
			
		||||
    @apply font-medium cursor-pointer select-none;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-input {
 | 
			
		||||
    @apply flex-1 text-sm min-w-[10rem];
 | 
			
		||||
    @apply bg-transparent border-none outline-none;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-action {
 | 
			
		||||
    @apply flex-initial shrink-0 flex items-center justify-center cursor-pointer w-12 h-10;
 | 
			
		||||
 | 
			
		||||
    &-icon {
 | 
			
		||||
      @apply h-4 opacity-50;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:hover &-icon.search {
 | 
			
		||||
      @apply hidden;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:not(:hover) &-icon.close {
 | 
			
		||||
      @apply hidden;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user