React 파일 관리자를 만들어 봅시다 19장: 파일 관리자 도구 모음의 개념

이전 장에서 목록 요청을 마무리했습니다. 이제 도구 모음에서 작업하겠습니다.

파일 관리자 도구 모음의 개념



그렇다면 파일 관리자 도구 모음의 기본 개념은 무엇입니까? 음, 간단합니다. 버튼 목록이 있고, 각 버튼에는 액션이 ​​있고, 각 액션에는 핸들러가 있습니다. 그게 다예요❕

이제 여기에는 UI AKA 버튼과 logic AKA 작업의 두 가지가 있습니다.

// src/apps/front-office/file-manager/components/Toolbar/Toolbar.tsx

import { Card } from "@mantine/core";

const buttons = [];

export default function Toolbar() {
  return (
    <>
      <Card shadow="sm">
        <div>Toolbar</div>
      </Card>
    </>
  );
}


빈 버튼을 제외하고 여기에 새로운 것을 추가하지 않았습니다. 홈 디렉토리로 이동하는 버튼을 추가해 보겠습니다.

// Toolbar.tsx
import { Card } from "@mantine/core";

const buttons = [
  HomeDirectoryButton,
];

export default function Toolbar() {
  return (
    <>
      <Card shadow="sm">
        <div>Toolbar</div>
      </Card>
    </>
  );
}


홈 디렉토리 버튼



이제 components/Toolbar/Buttons 디렉토리 아래의 툴바 안에 해당 버튼을 만들어 보겠습니다.

// HomeDirectoryButton.tsx
export default function HomeDirectoryButton() {
  return <div>HomeDirectoryButton</div>;
}


이제 가져와서 이 버튼을 렌더링해야 합니다. 그리드에서도 렌더링해 보겠습니다.

// Toolbar.tsx
import { Card, Grid } from "@mantine/core";
import HomeDirectoryButton from "./Buttons/HomeDirectoryButton";

const buttons = [
  HomeDirectoryButton,
];

export default function Toolbar() {
  return (
    <>
      <Card shadow="sm">
        <Grid>
          {buttons.map((Button, index) => (
            <Button key={index} />
          ))}
        </Grid>
      </Card>
    </>
  );
}


다음과 같습니다.



이제 버튼으로 렌더링해 보겠습니다.

import { ActionIcon, ThemeIcon, useMantineTheme } from "@mantine/core";
import { IconHome2 } from "@tabler/icons";

export default function HomeDirectoryButton() {
  const theme = useMantineTheme();
  return (
    <>
      <ActionIcon variant="subtle">
        <ThemeIcon variant="light" color={theme.colors.lime[1]}>
          <IconHome2 size={16} color={theme.colors.lime[9]} />
        </ThemeIcon>
      </ActionIcon>
    </>
  );
}


버튼을 Action Icon Component so it does not make any paddings around it으로 래핑하고 사이드바에 동일한 아이콘을 추가했습니다.

이제 그것을 tooltip 로 감싸자.

// HomeDirectoryButton.tsx
import { ActionIcon, ThemeIcon, Tooltip, useMantineTheme } from "@mantine/core";
import { IconHome2 } from "@tabler/icons";

export default function HomeDirectoryButton() {
  const theme = useMantineTheme();
  return (
    <>
      <Tooltip label="Home" position="bottom" transition="slide-up">
        <ActionIcon variant="subtle">
        <ThemeIcon variant="light" color={theme.colors.lime[1]}>
            <IconHome2 size={16} color={theme.colors.lime[9]} />
        </ThemeIcon>
        </ActionIcon>
      </Tooltip>
    </>
  );
}


당신은 다음과 같은 것을 볼 수 있습니다



Mantine Cards은 기본적으로 내부의 모든 오버플로를 숨기기 때문에 표시되도록 해야 합니다.
Toolbar.styles.tsx 파일을 만들고 이 스타일을 추가해 보겠습니다.

// Toolbar.styles.tsx
import styled from "@emotion/styled";
import { Card, CardProps } from "@mantine/core";
import { FC } from "react";

export const ToolbarWrapper = styled<FC<CardProps>>(Card)`
  label: ToolbarWrapper;
  overflow: visible; ;
`;


이제 가져와서 Card 구성 요소 대신 사용하겠습니다.

// Toolbar.tsx
import { Grid } from "@mantine/core";
import HomeDirectoryButton from "./Buttons/HomeDirectoryButton";
import { ToolbarWrapper } from "./Toolbar.styles";

const buttons = [
  HomeDirectoryButton,
];

export default function Toolbar() {
  return (
    <>
      <ToolbarWrapper shadow="sm">
        <Grid>
          {buttons.map((Button, index) => (
            <Button key={index} />
          ))}
        </Grid>
      </ToolbarWrapper>
    </>
  );
}


이제 잘 작동합니다

이제 버튼, 아이콘, 텍스트 및 래퍼 내부의 세 가지 요소에 대한 스타일을 만들어 봅시다.

// HomeDirectoryButton.tsx
import { ThemeIcon, Tooltip, useMantineTheme } from "@mantine/core";
import { IconHome2 } from "@tabler/icons";
import {
  ToolbarButtonText,
  ToolBarButtonWrapper,
  ToolbarIcon,
} from "../Toolbar.styles";

export default function HomeDirectoryButton() {
  const theme = useMantineTheme();
  return (
    <Tooltip label={"Home"} position="bottom" transition="slide-up">
      <ToolBarButtonWrapper>
        <ToolbarIcon variant="subtle">
          <ThemeIcon variant="light" color={theme.colors.lime[1]}>
            <IconHome2 size={16} color={theme.colors.lime[9]} />
          </ThemeIcon>
        </ToolbarIcon>
        <ToolbarButtonText>Home</ToolbarButtonText>
      </ToolBarButtonWrapper>
    </Tooltip>
  );
}


계속하기 전에 Mantine에 따라 definitions.d.ts 테마 매개변수를 재정의할 수 있도록 src 디렉토리에 styled라는 파일을 만들어야 합니다.

// definitions.d.ts
import "@emotion/react";
import type { MantineTheme } from "@mantine/core";

declare module "@emotion/react" {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  export interface Theme extends MantineTheme {}
}


테마에 아무것도 추가할 필요가 없기 때문에 eslint 오류를 비활성화했습니다.

이제 스타일링 섹션으로 이동합니다.

// Toolbar.styles.tsx
import styled from "@emotion/styled";
import { ActionIcon, ActionIconProps, Card, CardProps } from "@mantine/core";
import { FC } from "react";

// 👇🏻 We need to add FC<CardProps> to make it work with styled
export const ToolbarWrapper = styled<FC<CardProps>>(Card)`
  label: ToolbarWrapper;
  overflow: visible; ;
`;

// 👇🏻 the wrapper that will be used to wrap the icon and the text
export const ToolBarButtonWrapper = styled.div`
  label: ToolBarButtonWrapper;
  text-align: center;
  margin: 0 0.5rem;
  cursor: pointer;
`;

// 👇🏻 We need to add FC<ActionIconProps> to make it work with styled
export const ToolbarIcon = styled<FC<ActionIconProps>>(ActionIcon)`
  label: ToolbarIcon;
  width: 100%;
`;

// 👇🏻 the button text that will be displayed below the icon
export const ToolbarButtonText = styled.div`
  label: ToolbarButtonText;
  color: ${({ theme }) => theme.colors.gray[5]};
  font-weight: bold;
  font-size: 13px;
`;


이제 최종 모습은 이렇습니다



행위



지금은 간단한 작업 목록을 만들고 Kernel로 이동하여 getteractions 속성을 추가해 보겠습니다.

// Kernel.ts
...
  /**
   * Get kernel actions
   */
  public get actions() {
    return {
      navigateTo: this.load.bind(this),
    };
  }


여기서 첫 번째 작업은 이미 커널에 내장되어 있으며 navigateTo 작업이며 load 메서드의 래퍼일 뿐입니다.

이제 HomeDirectoryButton 구성 요소에서 사용해 보겠습니다.

// HomeDirectoryButton.tsx
import { ThemeIcon, Tooltip, useMantineTheme } from "@mantine/core";
import { IconHome2 } from "@tabler/icons";
import { useKernel } from "app/file-manager/hooks";
import {
  ToolbarButtonText,
  ToolBarButtonWrapper,
  ToolbarIcon,
} from "../Toolbar.styles";

export default function HomeDirectoryButton() {
  const theme = useMantineTheme();
  // we need to use the kernel to get the root path
  const kernel = useKernel();

  const actions = kernel.actions;

  return (
    <Tooltip label={"Home"} position="bottom" transition="slide-up">
      <ToolBarButtonWrapper onClick={() => actions.navigateTo(kernel.rootPath)}>
        <ToolbarIcon variant="subtle">
          <ThemeIcon variant="light" color={theme.colors.lime[1]}>
            <IconHome2 size={16} color={theme.colors.lime[9]} />
          </ThemeIcon>
        </ToolbarIcon>
        <ToolbarButtonText>Home</ToolbarButtonText>
      </ToolBarButtonWrapper>
    </Tooltip>
  );
}


지금까지는 좋았고 어려운 것도 쉬운 것도 없었습니다. 이제 create directory 버튼을 추가해 보겠습니다.

그러나 먼저 파일 관리자file-manager/actions에서 작업 디렉토리를 만들고 createDirectory.ts라는 파일을 만들고 다음 코드를 추가해야 합니다.

// createDirectory.ts
import Kernel from "../Kernel";

export default function createDirectory(kernel: Kernel) {
  return function create(directoryName: string) {

  }
}


색인 파일을 만들고 여기에서 모든 작업을 내보냅니다.

// index.ts
export { default as createDirectory } from "./createDirectory";


여기서 우리가 한 것은 커널을 수신하고 콜백 함수를 반환하는 함수를 만드는 것입니다. 이 콜백은 커널 작업 목록에서 호출할 때 직접 사용됩니다kernel.actions.createDirectory.

// Kernel.ts
// 👇🏻 import the createDirectory action
import { createDirectory } from "../actions";
...

  /**
   * Get kernel actions
   */
  public get actions() {
    return {
      navigateTo: this.load.bind(this),
      createDirectory: createDirectory(kernel);
    };
  }


이제 작업 목록을 업데이트하고 디렉터리 만들기 작업을 추가했습니다.

그러나 여기에 함정이 있습니다. actions getter를 호출할 때마다 새로운 createDirectory 함수가 생성되므로 한 번만 호출해야 합니다.

// Kernel.ts
...

  /**
   * Get kernel actions
   */
  public get actions() {
    // we added the following line to disable the annoying eslint message
    // as we can not use the this keyword in any getters i.e createDirectory.
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const kernel = this;

    return {
      navigateTo: this.load.bind(this),
      get createDirectory() {
        return createDirectory(kernel);
      },
    };
  }

createDirectory에서 getter Advantage를 다시 사용하면 사용해야 할 때만 호출하게 됩니다.

다음 장



다음 장에서는 create directory 작업과 버튼에 대한 작업도 시작합니다.

기사 저장소



Github Repository에서 챕터 파일을 볼 수 있습니다.

Don't forget the main branch has the latest updated code.



지금 어디 있는지 말해줘



이 시리즈를 저와 함께 후속 조치하는 경우 현재 위치와 어려움을 겪고 있는 부분을 알려주시면 최대한 도와드리겠습니다.

살람.

좋은 웹페이지 즐겨찾기