refactor: widget setting

This commit is contained in:
Tristan Yang
2024-11-07 11:28:26 +08:00
parent c2c23daf91
commit b9026ad89a
3 changed files with 209 additions and 194 deletions
-194
View File
@@ -1,194 +0,0 @@
// import { useState, MouseEvent } from "react";
// import dayjs from "dayjs";
import { useTranslation } from "react-i18next";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism";
import IconQuestion from "@/assets/icons/question.svg";
import { useAppSelector } from "../../app/store";
import Button from "../../components/styled/Button";
import Input from "../../components/styled/Input";
import useCopy from "../../hooks/useCopy";
import { shallowEqual } from "react-redux";
import LinkifyText from "@/components/LinkifyText";
const Row = ({
paramKey,
paramDefault,
remarks
}: {
paramKey: string;
paramDefault: string | number;
remarks: string;
}) => {
return (
<tr className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-50 border-b transition duration-300 ease-in-out md:hover:bg-gray-100 dark:md:hover:bg-gray-900">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">{paramKey}</td>
<td className="text-sm font-light px-6 py-4 whitespace-nowrap">
{paramKey == "theme-color" ? (
<span style={{ color: paramDefault as string }}> {paramDefault}</span>
) : (
paramDefault
)}
</td>
<td className="text-sm font-light px-6 py-4">
<LinkifyText linkPreview={false} text={remarks} mention={false} />
</td>
</tr>
);
};
export default function Widget() {
const loginUid = useAppSelector((store) => store.authData.user?.uid, shallowEqual);
const widgetLink = `${location.origin}/widget.html?host=${loginUid}`;
const { t } = useTranslation("setting", { keyPrefix: "widget" });
const { t: wt } = useTranslation("widget");
const { t: ct } = useTranslation();
const { copied, copy } = useCopy({ enableToast: false });
const copyLink = () => {
copy(widgetLink);
};
// const disableBtn = !reachLimit;
return (
<div className="flex flex-col justify-start items-start">
<div className="font-semibold dark:text-white">{t("tip")}</div>
<label htmlFor="code" className="font-semibold dark:text-white">
{t("code")}:
</label>
<SyntaxHighlighter id="code" language="html" style={vscDarkPlus} className="rounded">
{`<!-- ${t(
"code_comment"
)} -->\n<script \n data-host-id="${loginUid}" \n data-auto-reg="true" \n data-login-token="" \n data-title="" \n data-logo="" \n data-theme-color="#1fe1f9" \n data-close-width="48" \n data-close-height="48" \n data-open-width="380" \n data-open-height="680" \n data-welcome="Your custom welcome text" \n src="${
location.origin
}/widget.js" \n async \n></script>`}
</SyntaxHighlighter>
<div className="text-sm dark:text-white">{t("custom_style_tip")}:</div>
<SyntaxHighlighter id="code" language="html" style={vscDarkPlus} className="rounded">
{`<style>
#VOCECHAT_WIDGET {
left:10px /* left position */
bottom: 5px /* bottom position */
}
</style>`}
</SyntaxHighlighter>
<div className="font-semibold dark:text-white mt-5 mb-2">{t("config")}:</div>
<div className="w-full md:w-[700px] border border-solid border-gray-300 dark:border-gray-400 rounded overflow-auto md:overflow-hidden">
<table className="min-w-full table-auto">
<thead className="border-b bg-gray-50 dark:bg-gray-500">
<tr>
{[t("param_key"), t("default_value"), t("remark")].map((title) => (
<th
key={title}
scope="col"
className="text-sm font-bold text-gray-900 dark:text-white px-6 py-4 text-left whitespace-nowrap"
>
{title}
</th>
))}
</tr>
</thead>
<tbody>
{[
{
paramKey: "id",
paramDefault: "-",
remarks: t("param_id")
},
{
paramKey: "host-id",
paramDefault: 1,
remarks: t("param_host")
},
{
paramKey: "auto-reg",
paramDefault: "true",
remarks: t("param_auto_reg")
},
{
paramKey: "login-token",
paramDefault: `-`,
remarks: t("param_login_token")
},
{
paramKey: "title",
paramDefault: `[VoceChat Name]`,
remarks: t("param_title")
},
{
paramKey: "logo",
paramDefault: `[VoceChat Logo]`,
remarks: t("param_logo")
},
{
paramKey: "theme-color",
paramDefault: "#1fe1f9",
remarks: t("param_theme_color")
},
{
paramKey: "close-width",
paramDefault: `48(px)`,
remarks: t("param_close_width")
},
{
paramKey: "close-height",
paramDefault: `48(px)`,
remarks: t("param_close_height")
},
{
paramKey: "open-width",
paramDefault: `380(px)`,
remarks: t("param_open_width")
},
{
paramKey: "open-height",
paramDefault: `680(px)`,
remarks: t("param_open_height")
},
{
paramKey: "position",
paramDefault: `right`,
remarks: t("param_position")
},
{
paramKey: "welcome",
paramDefault: wt("welcome"),
remarks: t("param_welcome")
}
].map((row) => (
<Row key={row.paramKey} {...row} />
))}
</tbody>
<tfoot className="border-t border-solid border-gray-200 dark:border-gray-50 dark:bg-gray-500">
<tr>
<td colSpan={3} className="text-gray-400 dark:text-white px-5 py-3 text-sm">
* All the parameters are optional, and prefixed by{" "}
<i className="bg-gray-700 text-white px-1">data-</i>
</td>
</tr>
</tfoot>
</table>
</div>
<div className="mt-8">
<p className="text-sm mb-2 text-gray-500 dark:text-gray-50 flex flex-col md:flex-row gap-4">
{t("share_link")}{" "}
<a
className="text-primary-500 flex gap-1 items-center"
href="https://doc.voce.chat/widget"
target="_blank"
rel="noopener noreferrer"
>
<IconQuestion /> {t("widget_faq")}
</a>
</p>
<div className="w-full md:w-96 mb-3 relative">
<Input readOnly className={"large !pr-16"} value={widgetLink} />
<Button
onClick={copyLink}
className="ghost small border_less absolute right-1 top-1/2 -translate-y-1/2 dark:!text-primary-400"
>
{copied ? "Copied" : ct("action.copy")}
</Button>
</div>
</div>
</div>
);
}
+133
View File
@@ -0,0 +1,133 @@
import LinkifyText from "@/components/LinkifyText";
import React from "react";
import { useTranslation } from "react-i18next";
const Row = ({
paramKey,
paramDefault,
remarks
}: {
paramKey: string;
paramDefault: string | number;
remarks: string;
}) => {
return (
<tr className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-50 border-b transition duration-300 ease-in-out md:hover:bg-gray-100 dark:md:hover:bg-gray-900">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">{paramKey}</td>
<td className="text-sm font-light px-6 py-4 whitespace-nowrap">
{paramKey == "theme-color" ? (
<span style={{ color: paramDefault as string }}> {paramDefault}</span>
) : (
paramDefault
)}
</td>
<td className="text-sm font-light px-6 py-4">
<LinkifyText linkPreview={false} text={remarks} mention={false} />
</td>
</tr>
);
};
type Props = {};
const ConfigDetails = ({}: Props) => {
const { t } = useTranslation("setting", { keyPrefix: "widget" });
const { t: wt } = useTranslation("widget");
return (
<table className="min-w-full table-auto">
<thead className="border-b bg-gray-50 dark:bg-gray-500">
<tr>
{[t("param_key"), t("default_value"), t("remark")].map((title) => (
<th
key={title}
scope="col"
className="text-sm font-bold text-gray-900 dark:text-white px-6 py-4 text-left whitespace-nowrap"
>
{title}
</th>
))}
</tr>
</thead>
<tbody>
{[
{
paramKey: "id",
paramDefault: "-",
remarks: t("param_id")
},
{
paramKey: "host-id",
paramDefault: 1,
remarks: t("param_host")
},
{
paramKey: "auto-reg",
paramDefault: "true",
remarks: t("param_auto_reg")
},
{
paramKey: "login-token",
paramDefault: `-`,
remarks: t("param_login_token")
},
{
paramKey: "title",
paramDefault: `[VoceChat Name]`,
remarks: t("param_title")
},
{
paramKey: "logo",
paramDefault: `[VoceChat Logo]`,
remarks: t("param_logo")
},
{
paramKey: "theme-color",
paramDefault: "#1fe1f9",
remarks: t("param_theme_color")
},
{
paramKey: "close-width",
paramDefault: `48(px)`,
remarks: t("param_close_width")
},
{
paramKey: "close-height",
paramDefault: `48(px)`,
remarks: t("param_close_height")
},
{
paramKey: "open-width",
paramDefault: `380(px)`,
remarks: t("param_open_width")
},
{
paramKey: "open-height",
paramDefault: `680(px)`,
remarks: t("param_open_height")
},
{
paramKey: "position",
paramDefault: `right`,
remarks: t("param_position")
},
{
paramKey: "welcome",
paramDefault: wt("welcome"),
remarks: t("param_welcome")
}
].map((row) => (
<Row key={row.paramKey} {...row} />
))}
</tbody>
<tfoot className="border-t border-solid border-gray-200 dark:border-gray-50 dark:bg-gray-500">
<tr>
<td colSpan={3} className="text-gray-400 dark:text-white px-5 py-3 text-sm">
* All the parameters are optional, and prefixed by{" "}
<i className="bg-gray-700 text-white px-1">data-</i>
</td>
</tr>
</tfoot>
</table>
);
};
export default ConfigDetails;
+76
View File
@@ -0,0 +1,76 @@
// import { useState, MouseEvent } from "react";
// import dayjs from "dayjs";
import { useTranslation } from "react-i18next";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism";
import IconQuestion from "@/assets/icons/question.svg";
import { useAppSelector } from "@/app/store";
import Button from "@/components/styled/Button";
import Input from "@/components/styled/Input";
import useCopy from "@/hooks/useCopy";
import { shallowEqual } from "react-redux";
import ConfigDetails from "./ConfigDetails";
export default function Widget() {
const loginUid = useAppSelector((store) => store.authData.user?.uid, shallowEqual);
const widgetLink = `${location.origin}/widget.html?host=${loginUid}`;
const { t } = useTranslation("setting", { keyPrefix: "widget" });
const { t: ct } = useTranslation();
const { copied, copy } = useCopy({ enableToast: false });
const copyLink = () => {
copy(widgetLink);
};
// const disableBtn = !reachLimit;
return (
<div className="flex flex-col justify-start items-start">
<div className="font-semibold dark:text-white">{t("tip")}</div>
<label htmlFor="code" className="font-semibold dark:text-white">
{t("code")}:
</label>
<SyntaxHighlighter id="code" language="html" style={vscDarkPlus} className="rounded">
{`<!-- ${t(
"code_comment"
)} -->\n<script \n data-host-id="${loginUid}" \n data-auto-reg="true" \n data-login-token="" \n data-title="" \n data-logo="" \n data-theme-color="#1fe1f9" \n data-close-width="48" \n data-close-height="48" \n data-open-width="380" \n data-open-height="680" \n data-welcome="Your custom welcome text" \n src="${
location.origin
}/widget.js" \n async \n></script>`}
</SyntaxHighlighter>
<div className="text-sm dark:text-white">{t("custom_style_tip")}:</div>
<SyntaxHighlighter id="code" language="html" style={vscDarkPlus} className="rounded">
{`<style>
#VOCECHAT_WIDGET {
left:10px /* left position */
bottom: 5px /* bottom position */
}
</style>`}
</SyntaxHighlighter>
<div className="font-semibold dark:text-white mt-5 mb-2">{t("config")}:</div>
<div className="w-full md:w-[700px] border border-solid border-gray-300 dark:border-gray-400 rounded overflow-auto md:overflow-hidden">
{/* 配置说明 */}
<ConfigDetails />
</div>
<div className="mt-8">
<p className="text-sm mb-2 text-gray-500 dark:text-gray-50 flex flex-col md:flex-row gap-4">
{t("share_link")}{" "}
<a
className="text-primary-500 flex gap-1 items-center"
href="https://doc.voce.chat/widget"
target="_blank"
rel="noopener noreferrer"
>
<IconQuestion /> {t("widget_faq")}
</a>
</p>
<div className="w-full md:w-96 mb-3 relative">
<Input readOnly className={"large !pr-16"} value={widgetLink} />
<Button
onClick={copyLink}
className="ghost small border_less absolute right-1 top-1/2 -translate-y-1/2 dark:!text-primary-400"
>
{copied ? "Copied" : ct("action.copy")}
</Button>
</div>
</div>
</div>
);
}