feat: add custom css style for signup page and enhance css edit (#2880)

* feat: add custom css style for signup page and enhance css edit in signintable

* feat: change cssStyle to customCss

* feat: auto hide <style> label, fix display problem on providers, remove auto add providers in signup page

* fix: fix indent in signin items customCss and fix providers display in signup items

* fix: fix login replace logical
This commit is contained in:
DacongDA
2024-04-21 11:56:18 +08:00
committed by GitHub
parent d51af3378e
commit 90d502ab2b
51 changed files with 424 additions and 137 deletions

View File

@ -103,7 +103,7 @@ class SigninTable extends React.Component {
{name: "Providers", displayName: i18next.t("general:Providers")},
{name: "Agreement", displayName: i18next.t("signup:Agreement")},
{name: "Forgot password?", displayName: i18next.t("login:Forgot password?")},
{name: "Login button", displayName: i18next.t("login:Login button")},
{name: "Login button", displayName: i18next.t("login:Signin button")},
{name: "Signup link", displayName: i18next.t("general:Signup link")},
];
@ -187,15 +187,15 @@ class SigninTable extends React.Component {
return (
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror value={text}
options={{mode: "htmlmixed", theme: "material-darker"}}
<CodeMirror value={text?.replaceAll("<style>", "").replaceAll("</style>", "")}
options={{mode: "css", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
this.updateField(table, index, "label", value);
}}
/>
</div>
} title={i18next.t("application:CSS style")} trigger="click">
<Input value={text} onChange={e => {
<Input value={text?.replaceAll("<style>", "").replaceAll("</style>", "")} onChange={e => {
this.updateField(table, index, "label", e.target.value);
}} />
</Popover>

View File

@ -24,6 +24,27 @@ import "codemirror/lib/codemirror.css";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/htmlmixed/htmlmixed");
const EmailCss = ".signup-email{}\n.signup-email-input{}\n.signup-email-code{}\n.signup-email-code-input{}\n";
const PhoneCss = ".signup-phone{}\n.signup-phone-input{}\n.phone-code{}\n.signup-phone-code-input{}";
export const SignupTableDefaultCssMap = {
"Username": ".signup-username {}\n.signup-username-input {}",
"Display name": ".signup-first-name {}\n.signup-first-name-input{}\n.signup-last-name{}\n.signup-last-name-input{}\n.signup-name{}\n.signup-name-input{}",
"Affiliation": ".signup-affiliation{}\n.signup-affiliation-input{}",
"Country/Region": ".signup-country-region{}\n.signup-region-select{}",
"ID card": ".signup-idcard{}\n.signup-idcard-input{}",
"Password": ".signup-password{}\n.signup-password-input{}",
"Confirm password": ".signup-confirm{}",
"Email": EmailCss,
"Phone": PhoneCss,
"Email or Phone": EmailCss + PhoneCss,
"Phone or Email": EmailCss + PhoneCss,
"Invitation code": ".signup-invitation-code{}\n.signup-invitation-code-input{}",
"Agreement": ".login-agreement{}",
"Signup button": ".signup-button{}\n.signup-link{}",
"Providers": ".provider-img {\n width: 30px;\n margin: 5px;\n }\n .provider-big-img {\n margin-bottom: 10px;\n }\n ",
};
const {Option} = Select;
class SignupTable extends React.Component {
@ -44,7 +65,7 @@ class SignupTable extends React.Component {
}
addRow(table) {
const row = {name: Setting.getNewRowNameForTable(table, "Please select a signup item"), visible: true, required: true, rule: "None"};
const row = {name: Setting.getNewRowNameForTable(table, "Please select a signup item"), visible: true, required: true, rule: "None", customCss: ""};
if (table === undefined) {
table = [];
}
@ -89,6 +110,8 @@ class SignupTable extends React.Component {
{name: "Phone or Email", displayName: i18next.t("general:Phone or Email")},
{name: "Invitation code", displayName: i18next.t("application:Invitation code")},
{name: "Agreement", displayName: i18next.t("signup:Agreement")},
{name: "Signup button", displayName: i18next.t("signup:Signup button")},
{name: "Providers", displayName: i18next.t("general:Providers")},
{name: "Text 1", displayName: i18next.t("signup:Text 1")},
{name: "Text 2", displayName: i18next.t("signup:Text 2")},
{name: "Text 3", displayName: i18next.t("signup:Text 3")},
@ -109,6 +132,7 @@ class SignupTable extends React.Component {
value={getItemDisplayName(text)}
onChange={value => {
this.updateField(table, index, "name", value);
this.updateField(table, index, "customCss", SignupTableDefaultCssMap[value]);
}} >
{
Setting.getDeduplicatedArray(items, table, "name").map((item, index) => <Option key={index} value={item.name}>{item.displayName}</Option>)
@ -121,7 +145,7 @@ class SignupTable extends React.Component {
title: i18next.t("organization:Visible"),
dataIndex: "visible",
key: "visible",
width: "120px",
width: "80px",
render: (text, record, index) => {
if (record.name === "ID") {
return null;
@ -143,9 +167,9 @@ class SignupTable extends React.Component {
title: i18next.t("provider:Required"),
dataIndex: "required",
key: "required",
width: "120px",
width: "80px",
render: (text, record, index) => {
if (!record.visible) {
if (!record.visible || ["Signup button", "Providers"].includes(record.name)) {
return null;
}
@ -160,9 +184,9 @@ class SignupTable extends React.Component {
title: i18next.t("provider:Prompted"),
dataIndex: "prompted",
key: "prompted",
width: "120px",
width: "80px",
render: (text, record, index) => {
if (record.name === "ID") {
if (["ID", "Signup button", "Providers"].includes(record.name)) {
return null;
}
@ -181,7 +205,7 @@ class SignupTable extends React.Component {
title: i18next.t("signup:Label"),
dataIndex: "label",
key: "label",
width: "200px",
width: "150px",
render: (text, record, index) => {
if (record.name.startsWith("Text ")) {
return (
@ -209,6 +233,30 @@ class SignupTable extends React.Component {
);
},
},
{
title: i18next.t("application:Custom CSS"),
dataIndex: "customCss",
key: "customCss",
width: "180px",
render: (text, record, index) => {
return (
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}}>
<CodeMirror value={text ? text : SignupTableDefaultCssMap[record.name]}
options={{mode: "css", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
this.updateField(table, index, "customCss", value ? value : SignupTableDefaultCssMap[record.name]);
}}
/>
</div>
} title={i18next.t("application:CSS style")} trigger="click">
<Input value={text ? text : SignupTableDefaultCssMap[record.name]} onChange={e => {
this.updateField(table, index, "customCss", e.target.value ? e.target.value : SignupTableDefaultCssMap[record.name]);
}} />
</Popover>
);
},
},
{
title: i18next.t("signup:Placeholder"),
dataIndex: "placeholder",
@ -230,9 +278,9 @@ class SignupTable extends React.Component {
title: i18next.t("signup:Regex"),
dataIndex: "regex",
key: "regex",
width: "200px",
width: "180px",
render: (text, record, index) => {
if (record.name.startsWith("Text ") || record.name === "Password" || record.name === "Confirm password") {
if (record.name.startsWith("Text ") || ["Password", "Confirm password", "Signup button", "Provider"].includes(record.name)) {
return null;
}
@ -277,6 +325,11 @@ class SignupTable extends React.Component {
{id: "Signin", name: i18next.t("application:Signin")},
{id: "Signin (Default True)", name: i18next.t("application:Signin (Default True)")},
];
} else if (record.name === "Providers") {
options = [
{id: "big", name: i18next.t("application:Big icon")},
{id: "small", name: i18next.t("application:Small icon")},
];
}
if (options.length === 0) {
@ -304,7 +357,7 @@ class SignupTable extends React.Component {
<Button style={{marginRight: "5px"}} disabled={index === table.length - 1} icon={<DownOutlined />} size="small" onClick={() => this.downRow(table, index)} />
</Tooltip>
<Tooltip placement="topLeft" title={i18next.t("general:Delete")}>
<Button icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(table, index)} />
<Button disabled={record.name === "Signup button"} icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(table, index)} />
</Tooltip>
</div>
);