# 制作一个toolbar仪表盘

## 环境搭建

我们使用`logseq-plugin-template-react`为项目基础。

`git clone https://github.com/pengx17/logseq-plugin-template-react`

现在我们有了一个`手脚架`了。这个项目是用`pnpm`而不是传统的`npm`或者`yarn`，`pnpm`的优点大家使用之后一定会感觉到。使用方法和`npm`一致，把`npm`换成`pnpm`就行。

`pnpm install`安装依赖

## 项目结构

```
➜  logseq-plugin-template-react git:(master) tree -L 2
.
├── CHANGELOG.md
├── index.html
├── logo.svg
├── package.json
├── pnpm-lock.yaml
├── readme.md
├── release.config.js
├── renovate.json
├── src
│   ├── App.tsx # 页面代码写这，但是组件一般新建tsx。
│   ├── main.tsx # toolbar代码写这
│   └── utils.ts
├── tsconfig.json
└── vite.config.ts

1 directory, 13 files
```

## 注册toolbar

在 `main.tsx` 删掉原本的`logseq.provideUI`和`logseq.provideStyle`。

```typescript
logseq.provideStyle(css`
    div[data-injected-ui=${openIconName}-${pluginId}] {
      display: inline-flex;
      align-items: center;
      opacity: 0.55;
      font-weight: 500;
      padding: 0 5px;
      position: relative;
    }

    div[data-injected-ui=${openIconName}-${pluginId}]:hover {
      opacity: 0.9;
    }
  `);

  logseq.provideUI({
    key: openIconName,
    path: "#search",
    template: `
      <a data-on-click="show"
         style="opacity: .6; display: inline-flex;">⚙️</a>
    `,
  })
```

替换成：

```javascript
  logseq.provideStyle(css`
    .${openIconName} {
      width: 18px;
      height: 18px;
      margin: 2px 0.4em 0 0.4em;
      background-color: blue;
      border-radius: 4px;
      border: 1px solid #eee;
    }
  `);

  logseq.App.registerUIItem("toolbar", {
    key: "show-plugin-open",
    template: `
    <a data-on-click="show">
      <div class="${openIconName}"></div>
    </a>
  `,
  });
```

`logseq.App.registerUIItem`让我们向`toolbar`注册组件。

代码部分来源于`logseq-plugin-heatmap`项目。

现在我们运行`pnpm install && pnpm run build`。在`logseq`中载入，就可以在`toolbar`上看到我们的`UIItem`了。

![](/files/783DSndL75s00sV4eqLr)

当我们点击该蓝色图标时，就是我们的`页面`了。

![](/files/YTGYXvrv3oPvoNVDDJSZ)

## 新建页面

我们的目标是制做一个`仪表盘`。上面显示着`logseq`里的相关信息。在界面上参考`logseq-plugin-heatmap`

![](/files/59pq9dZVi7crW6daEGqP)

### 页面组件

新建`dashboard.tsx`和`dashboard.css`。

`dashborad.tsx`

```typescript
import React from "react";
import "./dashboard.css"

// eslint-disable-next-line react/display-name
export const Dashboard = React.forwardRef<HTMLDivElement>(({}, ref) => {
    return(
        <div className="dashboard-root">
            <div className="center">
                <h1>logseq borad!!!</h1>
            </div>
        </div>
    );
});
```

`dashboard.css`

```css
.dashboard-root {
    height: 8vh;
    width: 16vh;
    border-radius: 5%;
    display: flex;
    background-color: #e5e7eb;
}

.center{
    display: flex;
    margin: auto;
}
```

修改`App.tsx`

```typescript
import React, { useRef } from "react";
import { useAppVisible } from "./utils";
import { Dashboard } from "./dashboard";

function App() {
  const innerRef = useRef<HTMLDivElement>(null);
  const visible = useAppVisible();

  if (visible) {
    return (
      <main
          className="fixed inset-0 flex items-center justify-center"
          onClick={(e) => {
            if (!innerRef.current?.contains(e.target as any)) {
              window.logseq.hideMainUI();
            }
          }}
        >
        <Dashboard ref={innerRef}  />
      </main>
    );
  }
  return null;
}

export default App;
```

效果：

现在点击`UIItem`时就有一个小窗口出现在`logseq`正中央(因为`items-center justify-center`)。当我们点击`logseq`任意位置，都可以关闭该窗口。

![](/files/17MnJ9hbb7EDZe5cbxJ8)

### 调整页面位置

如果我们想像`logseq-plugin-heatmap`一样，页面出现在toolbar正下面。我们就需要调整页面的位置。

![](/files/59pq9dZVi7crW6daEGqP)

修改`dashboard.css`

```css
.dashboard-root {
    position: absolute;
    background-color: #e5e7eb;
    display: flex;
    width: 300px;
    height: 80px;
}

.center{
    display: flex;
    margin: auto;
}
```

修改`dashboard.tsx` 当然，这里我们引入了一个新的依赖，记得`pnpm install react-use`

```typescript
import React from "react";
import "./dashboard.css"
import { useWindowSize } from "react-use";

function useIconPosition() {
    const windowSize = useWindowSize();
    return React.useMemo(() => {
        const right = windowSize.width - 10;
        const bottom = 20;
        return { right, bottom };
    }, [windowSize]);
}

// eslint-disable-next-line react/display-name
export const Dashboard = React.forwardRef<HTMLDivElement>(({}, ref) => {
    const { bottom, right } = useIconPosition();
    console.log(bottom, right);
    return(
        <div
            ref={ref}
            className="dashboard-root"
             style={{ left: right - 400, top: bottom + 20 }}
            >
            <div className="center">
                <h1>logseq borad!!!</h1>
            </div>
        </div>
    );
});
```

其中`useWindowSize`是用来获取`logseq`的窗口位置的。而`useIconPosition`是我从`logseq-plugin-heatmap`里扒来的。

`main.tsx`中`<main>`的`className`修改为`className="absolute inset-0"`

现在的效果：

![](/files/xFtF8UMNyg9Pik0yLz9X)

### 页数内容

现在我们就要为我们的`dashboard`添加真正"有用"的功能了。

修改`dashboard.tsx`

```typescript
import React,{useEffect} from "react";
import "./dashboard.css"
import { useWindowSize } from "react-use";

function useIconPosition() {
    const windowSize = useWindowSize();
    return React.useMemo(() => {
        const right = windowSize.width - 10;
        const bottom = 20;
        return { right, bottom };
    }, [windowSize]);
}

// eslint-disable-next-line react/display-name
export const Dashboard = React.forwardRef<HTMLDivElement>(({}, ref) => {
    const { bottom, right } = useIconPosition();

    const [pageCount, setPageCount] = React.useState(0);
    useEffect(()=>{
        window.logseq.Editor.getAllPages().then(pages => {
            if (pages) {
                setPageCount(pages.length);
                }
            });
    },[])
    return(
        <div
            ref={ref}
            className="dashboard-root"
             style={{ left: right - 400, top: bottom + 80 }} // 这里80就是dashboard的高度。
            >
            <div className="center">
                <h1> 一共有 {pageCount} 个页面 </h1>
            </div>
        </div>
    );
});
```

现在当我们点成`UIItem`，我们就能看到我们一共拥有多少页了。

![](/files/IlL38ZeWqvuwJiHeOnhz)

> 本文代码位置 <https://github.com/CorrectRoadH/logseq-plugins-develop-tutorial/tree/main/code/logseq-dashboard>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://correctroad.gitbook.io/logseq-plugins-in-action/chapter-1/make-a-toolbar-dashboard.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
