diff --git a/packages/app/src/components/WidgetItemPreview/index.jsx b/packages/app/src/components/WidgetItemPreview/index.jsx
new file mode 100644
index 00000000..5b887ecc
--- /dev/null
+++ b/packages/app/src/components/WidgetItemPreview/index.jsx
@@ -0,0 +1,92 @@
+import React from "react"
+import * as antd from "antd"
+import Image from "components/Image"
+import { Icons } from "components/Icons"
+
+import "./index.less"
+
+export default (props) => {
+ const { manifest } = props
+
+ const isInstalled = app.cores.widgets.isInstalled(manifest._id)
+ const isVisible = app.cores.widgets.isVisible(manifest._id)
+
+ const removeItem = () => {
+ antd.Modal.confirm({
+ title: "Are you sure?",
+ content: "Do you want to remove this widget?",
+ okText: "Yes",
+ okType: "danger",
+ cancelText: "No",
+ onOk: () => {
+ props.onRemove()
+ }
+ })
+ }
+
+ if (!manifest) {
+ return
+ }
+
+ return
+
+ {
+ manifest.iconUrl &&
+
+
+ }
+
+
+
+ {
+ manifest.name
+ }
+
+
+
+ {
+ manifest.description
+ }
+
+ v{
+ manifest.version
+ }
+
+
+
+
+ {
+ isInstalled &&
}
+ unCheckedChildren={
}
+ defaultChecked={isVisible}
+ onChange={(checked) => {
+ props.onChangeVisible(checked)
+ }}
+ />
+ }
+
+
:
}
+ onClick={isInstalled ? props.onUpdate : props.onInstall}
+ type={isInstalled ? "default" : "primary"}
+ />
+
+ {
+ isInstalled &&
}
+ onClick={() => {
+ removeItem()
+ }}
+ danger
+ />
+ }
+
+
+}
\ No newline at end of file
diff --git a/packages/app/src/components/WidgetItemPreview/index.less b/packages/app/src/components/WidgetItemPreview/index.less
new file mode 100644
index 00000000..7a7fda88
--- /dev/null
+++ b/packages/app/src/components/WidgetItemPreview/index.less
@@ -0,0 +1,48 @@
+.widget_preview_item {
+ display: flex;
+ flex-direction: row;
+
+ align-items: center;
+ justify-content: space-between;
+
+ padding: 10px;
+
+ border: 1px var(--border-color) solid;
+ border-radius: 12px;
+
+ .widget_preview_item_info {
+ display: flex;
+ flex-direction: row;
+
+ gap: 20px;
+
+ .widget_preview_item_info_icon {
+ display: flex;
+ flex-direction: row;
+
+ align-items: center;
+ justify-content: center;
+
+ align-self: center;
+
+ height: 60px;
+ width: 60px;
+
+ img {
+ height: 100%;
+ width: 100%;
+
+ object-fit: contain;
+ }
+ }
+ }
+
+ .widget_preview_item_actions {
+ display: flex;
+ flex-direction: row;
+
+ align-items: center;
+
+ gap: 10px;
+ }
+}
\ No newline at end of file