feat(signing): 将签署占位符改为原子节点并支持多选选项组
This commit is contained in:
@@ -3,14 +3,15 @@ import { computed, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
import type { CampusRecord, DepartmentRecord } from '@/api/management/types'
|
||||
import type { SigningFieldDef, SigningFieldKind } from '@/api/workbench/types'
|
||||
import {
|
||||
buildFieldToken,
|
||||
buildGenericTextToken,
|
||||
allocateCustomFieldId,
|
||||
collectFieldDefs,
|
||||
findDuplicateFields,
|
||||
GENERIC_TEXT_FIELD_LABEL,
|
||||
SIGNING_FIELD_KIND_LABELS,
|
||||
SIGNING_FIELD_PRESETS,
|
||||
upgradeFieldTokensToStructured,
|
||||
} from '@/utils/signing-fields'
|
||||
|
||||
import EditorWangPane from './editors/EditorWangPane.vue'
|
||||
@@ -39,10 +40,16 @@ const savePermission = computed(() =>
|
||||
// Word 自维护方案:科室把文书从 Word/WPS 直接粘贴进来(保留表格与基本格式),
|
||||
// 或上传 .docx 由 mammoth 转换;签署时由交互管线识别"勾选"表并转为签署域。
|
||||
// 编辑引擎固定为 WangEditor(MIT)。更换引擎只需新增一个实现 EditorPaneHandle 的面板组件,
|
||||
// 注意把 Word 粘贴的归一化处理重新挂到新引擎的粘贴钩子上(WangEditor 见 EditorWangPane 的 customPaste)。
|
||||
// 注意把 Word 粘贴的归一化处理重新挂到新引擎的粘贴钩子上(WangEditor 见 EditorWangPane 的 customPaste),
|
||||
// 并把占位符的元素节点与渲染钩子重新注册一遍(见 utils/signing-field-node)。
|
||||
interface EditorPaneHandle {
|
||||
getText: () => string
|
||||
insertText: (text: string) => void
|
||||
insertField: (field: SigningFieldDef) => void
|
||||
/** 就地改写某个字段的占位符,返回命中的节点数;0 表示正文里已经没有它 */
|
||||
updateField: (fieldId: string, patch: Partial<Omit<SigningFieldDef, 'id'>>) => number
|
||||
/** 就地删掉某个字段的占位符,返回命中的节点数 */
|
||||
removeField: (fieldId: string) => number
|
||||
}
|
||||
|
||||
const valueHtml = ref('<p><br></p>')
|
||||
@@ -50,13 +57,20 @@ const docxInput = ref<HTMLInputElement | null>(null)
|
||||
const importing = ref(false)
|
||||
const importMessage = ref('')
|
||||
const paneRef = ref<EditorPaneHandle | null>(null)
|
||||
/** 打开时若把旧式 {…} 占位符升级成了原子占位符,这里放一句说明(不静默改内容) */
|
||||
const upgradeNotice = ref('')
|
||||
/** 正在配置的填写项字段键;空串表示没有选中 */
|
||||
const selectedFieldId = ref('')
|
||||
|
||||
// 占位符分两类:
|
||||
// ① 目录里的字段(utils/signing-fields 的 SIGNING_FIELD_PRESETS):取值有固定来源,
|
||||
// 签署时按字段键取 HIS / 患者就诊快照自动填充,其中签名是独立控件类型——
|
||||
// 签字后签名图作为该字段取值落回文书原本的签名位,不需要再替换文字;
|
||||
// ② 通用文本项(现场手填的输入框,如与患者关系、受托人姓名):没有系统取值来源,
|
||||
// 默认写 {文本框},签署时渲染成一个空文本框,名称在正文里改即可,见 insertGenericTextField。
|
||||
// 默认写「文本框」,签署时渲染成一个空文本框,名称在配置面板里改即可。
|
||||
//
|
||||
// 两类插入的都是**结构化占位符元素节点**(正文里存成 <span data-field>):
|
||||
// 点一下即整块选中、一次退格整块删除,字段键 / 类型 / 必填 / 选项 / 多选都在元素上。
|
||||
|
||||
const form = reactive<TemplateEditorForm>({
|
||||
templateCode: '',
|
||||
@@ -96,9 +110,24 @@ watch(
|
||||
versionNo: template?.version ?? 'v1',
|
||||
contentHtml: template?.contentHtml ?? '',
|
||||
})
|
||||
valueHtml.value = template?.contentHtml || '<p><br></p>'
|
||||
|
||||
// 存量正文里的占位符是纯文本 {患者姓名},删一个要按五六次退格。
|
||||
// 打开时统一升级成结构化占位符(原子节点、一次退格整块删除)。
|
||||
// 升级沿用同一套解析口径,字段键前后完全一致,历史 fieldAnswers 不受影响;
|
||||
// 正文里没有 { 时这一步原样返回,不会白白做一次 DOM 往返。
|
||||
const rawContent = template?.contentHtml || '<p><br></p>'
|
||||
const upgradedContent = upgradeFieldTokensToStructured(rawContent)
|
||||
|
||||
upgradeNotice.value =
|
||||
upgradedContent === rawContent
|
||||
? ''
|
||||
: '已把正文里的旧式 {…} 占位符升级为可整块删除的占位符(字段口径不变)。'
|
||||
|
||||
form.contentHtml = upgradedContent
|
||||
valueHtml.value = upgradedContent
|
||||
syncDepartmentOptions()
|
||||
importMessage.value = ''
|
||||
selectedFieldId.value = ''
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
@@ -120,24 +149,159 @@ function insertContent(text: string) {
|
||||
paneRef.value?.insertText(text)
|
||||
}
|
||||
|
||||
function insertField(field: (typeof SIGNING_FIELD_PRESETS)[number]) {
|
||||
insertContent(buildFieldToken(field))
|
||||
/**
|
||||
* 插入目录里的字段(患者姓名、签名、日期……)。
|
||||
*
|
||||
* 进的是**结构化占位符元素节点**,不是一段文字:点一下即整块选中,
|
||||
* 一次退格整块删除;字段键与类型随节点走,不靠"第几次出现"推断。
|
||||
*/
|
||||
function insertField(field: SigningFieldDef) {
|
||||
paneRef.value?.insertField(field)
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入通用文本项:现场手填的输入框,默认 {文本框}。
|
||||
* 插入通用文本项:现场手填的输入框,默认叫「文本框」。
|
||||
*
|
||||
* 每插一个就是一个独立填写项(字段键按出现位置编号,见 signing-fields 的 resolveFieldByLabel),
|
||||
* 所以两处文本框天然是两份取值,不需要为了区分而改名字。
|
||||
* 名称只决定文书里显示的文字:改成「与患者关系」是为了读起来像文书,不影响取值归属。
|
||||
* 每插一个就是一个独立填写项,所以字段键必须**当场取一个没被占用的**
|
||||
* (见 allocateCustomFieldId)——两个文本框是两处要填的内容,共用一个键才是错的。
|
||||
* 名称只决定文书里显示的文字:改成「与患者关系」只是为了读起来像文书,
|
||||
* 不影响它是哪个字段,也不影响历史取值。
|
||||
*/
|
||||
function insertGenericTextField() {
|
||||
insertContent(buildGenericTextToken())
|
||||
const label = GENERIC_TEXT_FIELD_LABEL
|
||||
|
||||
paneRef.value?.insertField({
|
||||
id: allocateCustomFieldId(valueHtml.value, label),
|
||||
label,
|
||||
kind: 'text',
|
||||
required: false,
|
||||
options: [],
|
||||
})
|
||||
}
|
||||
|
||||
/** 已插入的填写项:让科室在保存前确认签名位、日期位有没有漏 */
|
||||
/** 已插入的填写项:让科室在保存前确认签名位、日期位有没有漏,并点进去改配置 */
|
||||
const detectedFields = computed(() => collectFieldDefs(valueHtml.value))
|
||||
|
||||
/** 正在配置的那一项(从 detectedFields 里现取,保证面板显示的就是正文里的口径) */
|
||||
const selectedField = computed(
|
||||
() => detectedFields.value.find((field) => field.id === selectedFieldId.value) ?? null,
|
||||
)
|
||||
|
||||
/**
|
||||
* 配置草稿。
|
||||
*
|
||||
* 与 selectedField 分开保存:面板上改到一半、还没点「应用修改」时,
|
||||
* 正文(valueHtml)不能跟着变——那会让编辑区每次敲键盘都重排一次。
|
||||
*/
|
||||
const fieldDraft = reactive({
|
||||
label: '',
|
||||
kind: 'text' as SigningFieldKind,
|
||||
required: false,
|
||||
optionsText: '',
|
||||
multi: false,
|
||||
risk: '',
|
||||
})
|
||||
|
||||
function syncDraft(field: SigningFieldDef | null) {
|
||||
fieldDraft.label = field?.label ?? ''
|
||||
fieldDraft.kind = field?.kind ?? 'text'
|
||||
fieldDraft.required = field?.required ?? false
|
||||
// 选项用顿号展示:科室更习惯「同意、不同意」这种写法,逗号也能识别
|
||||
fieldDraft.optionsText = (field?.options ?? []).join('、')
|
||||
// 缺省口径与 signing-fields 的 SigningFieldDef.multi 一致:勾选类默认可多选
|
||||
fieldDraft.multi = field?.multi ?? field?.kind === 'checkbox'
|
||||
fieldDraft.risk = field?.risk ?? ''
|
||||
}
|
||||
|
||||
// 只在"选中项变了"时对齐草稿。不要 watch selectedField —— 它是 computed,
|
||||
// 正文每敲一个字都会重算并换掉对象引用,那样会把面板上没提交的编辑冲掉。
|
||||
watch(
|
||||
() => selectedFieldId.value,
|
||||
(fieldId) => {
|
||||
syncDraft(detectedFields.value.find((field) => field.id === fieldId) ?? null)
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
/** 点正文里的胶囊:直接选中并刷新草稿(同一个胶囊连点两次也应把草稿复原) */
|
||||
function selectFieldFromEditor(field: SigningFieldDef) {
|
||||
selectedFieldId.value = field.id
|
||||
syncDraft(field)
|
||||
}
|
||||
|
||||
/** 点列表项:再点一次收起,也顺带把草稿复原 */
|
||||
function toggleField(fieldId: string) {
|
||||
selectedFieldId.value = selectedFieldId.value === fieldId ? '' : fieldId
|
||||
}
|
||||
|
||||
/** 选项文本 → 选项数组。顿号、中英文逗号、竖线都当分隔符(竖线与 data-options 口径一致) */
|
||||
function parseOptions(text: string): string[] {
|
||||
return text
|
||||
.split(/[、,,|]/)
|
||||
.map((option) => option.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
function applyFieldDraft() {
|
||||
const field = selectedField.value
|
||||
|
||||
if (!field) {
|
||||
return
|
||||
}
|
||||
|
||||
const label = fieldDraft.label.trim()
|
||||
|
||||
if (!label) {
|
||||
ElMessage.error('填写项名称不能为空')
|
||||
return
|
||||
}
|
||||
|
||||
const needsOptions = fieldDraft.kind === 'choice' || fieldDraft.kind === 'checkbox'
|
||||
const options = needsOptions ? parseOptions(fieldDraft.optionsText) : []
|
||||
|
||||
if (needsOptions && !options.length) {
|
||||
ElMessage.error('单选 / 勾选至少要有一个选项')
|
||||
return
|
||||
}
|
||||
|
||||
// 字段键(field.id)刻意保持不变:id 是取值的归属,改叫法不该让历史取值对不上。
|
||||
// 目录外的自定义文本项也一样——它的键里虽然带着旧名字,但那只是个内部标识。
|
||||
//
|
||||
// 改的是**编辑器模型**而不是 valueHtml 字符串:字符串往返要经过 setHtml,
|
||||
// 会重建整篇文档——用户此刻的光标还停在正文里,旧选区在新 DOM 上找不到位置就抛异常,
|
||||
// 而且光标也会丢。改模型两个问题都没有。
|
||||
const changed = paneRef.value?.updateField(field.id, {
|
||||
label,
|
||||
kind: fieldDraft.kind,
|
||||
required: fieldDraft.required,
|
||||
options,
|
||||
multi: options.length ? fieldDraft.multi : undefined,
|
||||
risk: fieldDraft.risk.trim() || undefined,
|
||||
})
|
||||
|
||||
if (!changed) {
|
||||
ElMessage.warning(`正文里已经没有「${field.label}」了,请重新选择要修改的填写项`)
|
||||
selectedFieldId.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
ElMessage.success(`已更新「${label}」(正文里 ${changed} 处)`)
|
||||
}
|
||||
|
||||
function removeField() {
|
||||
const field = selectedField.value
|
||||
|
||||
if (!field) {
|
||||
return
|
||||
}
|
||||
|
||||
// 整项作废:正文里它的每一处出现都删掉(签名位在每页都出现是常态)
|
||||
const changed = paneRef.value?.removeField(field.id) ?? 0
|
||||
|
||||
selectedFieldId.value = ''
|
||||
ElMessage.success(`已删除「${field.label}」(正文里 ${changed} 处)`)
|
||||
}
|
||||
|
||||
const placeholderHints = computed(() => {
|
||||
const hints: string[] = []
|
||||
const ids = new Set(detectedFields.value.map((field) => field.id))
|
||||
@@ -179,6 +343,10 @@ async function handleDocxChange(event: Event) {
|
||||
const arrayBuffer = await file.arrayBuffer()
|
||||
const mammoth = await import('mammoth/mammoth.browser')
|
||||
const result = await mammoth.convertToHtml({ arrayBuffer })
|
||||
// 已知问题(既有,与本次占位符改动无关):编辑器已有光标时这一句会让 wangEditor 抛一条
|
||||
// 未捕获的 promise 异常——setHtml 内部会 e.focus(),把缓存的上次选区装回去,
|
||||
// 新正文的节点还没绑上 DOM 就先做了一次 DOM 同步。
|
||||
// 正文仍然会正常导入(异常发生在同步选区那一步),要彻底修需要重建编辑器实例,另行处理。
|
||||
valueHtml.value = result.value || '<p><br></p>'
|
||||
importMessage.value = result.messages.length
|
||||
? `已导入,${result.messages.length} 条转换提示(部分 Word 特性可能未还原)`
|
||||
@@ -335,18 +503,81 @@ function save() {
|
||||
|
||||
<div class="placeholder-check">
|
||||
<div class="placeholder-check__head">
|
||||
<strong>占位符检查</strong>
|
||||
<span>{{ detectedFields.length }} 个填写项</span>
|
||||
<strong>填写项</strong>
|
||||
<span>{{ detectedFields.length }} 个</span>
|
||||
<span v-if="upgradeNotice" class="placeholder-check__notice">{{ upgradeNotice }}</span>
|
||||
</div>
|
||||
<div v-if="detectedFields.length" class="placeholder-check__list">
|
||||
<span v-for="field in detectedFields" :key="field.id" class="placeholder-check__item">
|
||||
<button
|
||||
v-for="field in detectedFields"
|
||||
:key="field.id"
|
||||
type="button"
|
||||
class="placeholder-check__item"
|
||||
:class="{ 'is-active': field.id === selectedFieldId }"
|
||||
:title="`点击配置「${field.label}」的名称 / 类型 / 必填 / 选项`"
|
||||
@click="toggleField(field.id)"
|
||||
>
|
||||
{{ field.label }}
|
||||
<em>{{ kindLabels[field.kind] }}</em>
|
||||
</span>
|
||||
<i v-if="field.required">必填</i>
|
||||
<i v-if="field.options.length">{{ field.options.length }} 选项</i>
|
||||
</button>
|
||||
</div>
|
||||
<p v-else class="placeholder-check__empty">
|
||||
文书中还没有任何填写项,签署时不会采集患者填写内容。
|
||||
</p>
|
||||
|
||||
<div v-if="selectedField" class="field-config">
|
||||
<div class="field-config__head">
|
||||
<strong>配置「{{ selectedField.label }}」</strong>
|
||||
<span>字段键 {{ selectedField.id }}(改名称不影响取值归属)</span>
|
||||
</div>
|
||||
<div class="field-config__row">
|
||||
<label class="field-config__item">
|
||||
<span>名称</span>
|
||||
<input v-model="fieldDraft.label" type="text" />
|
||||
</label>
|
||||
<label class="field-config__item">
|
||||
<span>类型</span>
|
||||
<select v-model="fieldDraft.kind">
|
||||
<option v-for="(text, kind) in kindLabels" :key="kind" :value="kind">
|
||||
{{ text }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field-config__item grow">
|
||||
<span>高危值(取值命中即标为异常项)</span>
|
||||
<input v-model="fieldDraft.risk" type="text" placeholder="如 否" />
|
||||
</label>
|
||||
<label class="field-config__check">
|
||||
<input v-model="fieldDraft.required" type="checkbox" />
|
||||
<span>必填</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
v-if="fieldDraft.kind === 'choice' || fieldDraft.kind === 'checkbox'"
|
||||
class="field-config__row"
|
||||
>
|
||||
<label class="field-config__item grow">
|
||||
<span>选项(用、或 | 分隔)</span>
|
||||
<input v-model="fieldDraft.optionsText" type="text" placeholder="如 同意、不同意" />
|
||||
</label>
|
||||
<label class="field-config__check">
|
||||
<input v-model="fieldDraft.multi" type="checkbox" />
|
||||
<span>可多选</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="field-config__actions">
|
||||
<button type="button" class="field-config__button primary" @click="applyFieldDraft">
|
||||
应用修改
|
||||
</button>
|
||||
<button type="button" class="field-config__button danger" @click="removeField">
|
||||
删除该项
|
||||
</button>
|
||||
<span>改动会作用到正文里该项的每一处出现,保存文书后生效</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul v-if="placeholderHints.length" class="placeholder-check__hints">
|
||||
<li v-for="hint in placeholderHints" :key="hint">{{ hint }}</li>
|
||||
</ul>
|
||||
@@ -374,8 +605,8 @@ function save() {
|
||||
<span v-else class="docx-hint">
|
||||
建议从 Word/WPS
|
||||
中全选复制文书后直接粘贴到下方编辑区;需要患者勾选的内容可点上方「插入勾选框」按钮插入(光标停在表格单元格里就插到该单元格),或用表头含「勾选」列的表格承载;
|
||||
需要患者现场填写的内容(与患者关系、受托人姓名等)点「文本框」插入输入框占位符,插几个就是几处独立填写、各填各的;把名称改成实际叫法只是为了读起来像文书。
|
||||
占位符与勾选框在编辑区会显示成带类型标签的胶囊,便于和正文区分。
|
||||
需要患者现场填写的内容(与患者关系、受托人姓名等)点「文本框」插入输入框占位符,插几个就是几处独立填写、各填各的。
|
||||
占位符在编辑区显示成带类型标签的胶囊:点一下即整块选中,按一次退格就整块删除;名称、类型、必填、选项在下方「填写项」里点开改。
|
||||
</span>
|
||||
</div>
|
||||
<p class="docx-header-note">
|
||||
@@ -388,6 +619,7 @@ function save() {
|
||||
ref="paneRef"
|
||||
:model-value="valueHtml"
|
||||
@update:model-value="valueHtml = $event"
|
||||
@select-field="selectFieldFromEditor"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -578,12 +810,22 @@ function save() {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* 打开文书时若升级了旧式占位符,在这里说一声——不静默改内容 */
|
||||
.placeholder-check__notice {
|
||||
padding: 2px 8px;
|
||||
color: var(--brand);
|
||||
font-size: 11px;
|
||||
background: var(--brand-l);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.placeholder-check__list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
/* 每一项都是按钮:点开即可改名称 / 类型 / 必填 / 选项,再点一次收起 */
|
||||
.placeholder-check__item {
|
||||
display: inline-flex;
|
||||
gap: 5px;
|
||||
@@ -594,6 +836,17 @@ function save() {
|
||||
background: #f4f8fa;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.placeholder-check__item:hover {
|
||||
border-color: var(--brand);
|
||||
}
|
||||
|
||||
.placeholder-check__item.is-active {
|
||||
color: #fff;
|
||||
background: var(--brand);
|
||||
border-color: var(--brand);
|
||||
}
|
||||
|
||||
.placeholder-check__item em {
|
||||
@@ -602,6 +855,137 @@ function save() {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.placeholder-check__item i {
|
||||
padding: 0 5px;
|
||||
color: var(--mut);
|
||||
font-size: 10px;
|
||||
font-style: normal;
|
||||
background: rgb(0 0 0 / 5%);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.placeholder-check__item.is-active em,
|
||||
.placeholder-check__item.is-active i {
|
||||
color: #fff;
|
||||
background: rgb(255 255 255 / 22%);
|
||||
}
|
||||
|
||||
/* ---- 填写项配置 ---- */
|
||||
|
||||
.field-config {
|
||||
padding: 9px 10px;
|
||||
margin-top: 8px;
|
||||
background: #f8fbfc;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.field-config__head {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: baseline;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.field-config__head strong {
|
||||
color: var(--ink);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
|
||||
.field-config__head span {
|
||||
color: var(--mut);
|
||||
font-size: 10.5px;
|
||||
}
|
||||
|
||||
.field-config__row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: flex-end;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.field-config__item {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.field-config__item.grow {
|
||||
flex: 1;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.field-config__item > span {
|
||||
display: block;
|
||||
margin-bottom: 3px;
|
||||
color: var(--ink);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.field-config__item input,
|
||||
.field-config__item select {
|
||||
width: 100%;
|
||||
padding: 5px 7px;
|
||||
color: var(--ink);
|
||||
font-size: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.field-config__item input:focus,
|
||||
.field-config__item select:focus {
|
||||
border-color: var(--brand);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.field-config__check {
|
||||
display: inline-flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
padding-bottom: 6px;
|
||||
color: var(--ink);
|
||||
font-size: 11.5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.field-config__actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.field-config__actions > span {
|
||||
color: var(--mut);
|
||||
font-size: 10.5px;
|
||||
}
|
||||
|
||||
.field-config__button {
|
||||
padding: 4px 11px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 700;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.field-config__button.primary {
|
||||
color: #fff;
|
||||
background: var(--brand);
|
||||
border: 1px solid var(--brand);
|
||||
}
|
||||
|
||||
.field-config__button.danger {
|
||||
color: var(--danger, #c0392b);
|
||||
background: #fff;
|
||||
border: 1px solid currentcolor;
|
||||
}
|
||||
|
||||
.field-config__button:hover {
|
||||
filter: brightness(0.96);
|
||||
}
|
||||
|
||||
.placeholder-check__empty {
|
||||
margin: 0;
|
||||
color: var(--mut);
|
||||
|
||||
Reference in New Issue
Block a user