Improve QWord ribbon fidelity
This commit is contained in:
+266
-98
@@ -1,9 +1,12 @@
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
AlignCenter,
|
||||
AlignJustify,
|
||||
AlignLeft,
|
||||
AlignRight,
|
||||
Bold,
|
||||
ClipboardPaste,
|
||||
Copy,
|
||||
Download,
|
||||
FileText,
|
||||
FileUp,
|
||||
@@ -11,10 +14,17 @@ import {
|
||||
Italic,
|
||||
Link,
|
||||
List,
|
||||
ListOrdered,
|
||||
PaintBucket,
|
||||
RemoveFormatting,
|
||||
Replace,
|
||||
Save,
|
||||
Scissors,
|
||||
Search,
|
||||
SeparatorHorizontal,
|
||||
Strikethrough,
|
||||
Subscript,
|
||||
Superscript,
|
||||
Type,
|
||||
Underline
|
||||
} from "lucide-react";
|
||||
@@ -31,6 +41,11 @@ interface QWordProps {
|
||||
onChange: (document: WordDocument) => void;
|
||||
}
|
||||
|
||||
type PageSearchWindow = Window &
|
||||
typeof globalThis & {
|
||||
find?: (query: string) => boolean;
|
||||
};
|
||||
|
||||
function countWords(html: string) {
|
||||
const text = html.replace(/<[^>]+>/g, " ").replace(/ /g, " ").trim();
|
||||
return text ? text.split(/\s+/).length : 0;
|
||||
@@ -94,6 +109,32 @@ const highlightSwatches = [
|
||||
{ color: "#ffffff", label: "Без подсветки" }
|
||||
];
|
||||
|
||||
const fontFamilyOptions = ["Calibri", "Aptos", "Arial", "Times New Roman", "Courier New"];
|
||||
const fontSizeOptions = [9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 36];
|
||||
const fontSizeCommandMap: Record<number, string> = {
|
||||
9: "1",
|
||||
10: "2",
|
||||
11: "2",
|
||||
12: "3",
|
||||
14: "4",
|
||||
16: "4",
|
||||
18: "5",
|
||||
20: "5",
|
||||
24: "6",
|
||||
28: "6",
|
||||
36: "7"
|
||||
};
|
||||
const styleGalleryOptions = [
|
||||
{ value: "p", label: "Обычный" },
|
||||
{ value: "h1", label: "Заголовок 1" },
|
||||
{ value: "h2", label: "Заголовок 2" },
|
||||
{ value: "blockquote", label: "Цитата" }
|
||||
];
|
||||
|
||||
function findInPage(query: string) {
|
||||
return (window as PageSearchWindow).find?.(query) ?? false;
|
||||
}
|
||||
|
||||
const defaultPageViewHeight = 1180;
|
||||
|
||||
function pageHeightFromStyles(element: HTMLElement) {
|
||||
@@ -152,6 +193,45 @@ export function QWord({ document, onChange }: QWordProps) {
|
||||
updateHtml();
|
||||
}
|
||||
|
||||
function applyFontFamily(fontFamily: string) {
|
||||
if (fontFamily) {
|
||||
runCommand("fontName", fontFamily);
|
||||
}
|
||||
}
|
||||
|
||||
function applyFontSize(fontSize: string) {
|
||||
const pointSize = Number(fontSize);
|
||||
if (Number.isFinite(pointSize)) {
|
||||
runCommand("fontSize", fontSizeCommandMap[pointSize] ?? "3");
|
||||
}
|
||||
}
|
||||
|
||||
function findText() {
|
||||
const query = window.prompt("Найти текст");
|
||||
if (!query) {
|
||||
return;
|
||||
}
|
||||
|
||||
editorRef.current?.focus();
|
||||
findInPage(query);
|
||||
}
|
||||
|
||||
function replaceText() {
|
||||
const query = window.prompt("Найти текст для замены");
|
||||
if (!query) {
|
||||
return;
|
||||
}
|
||||
|
||||
editorRef.current?.focus();
|
||||
if (!findInPage(query)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const replacement = window.prompt("Заменить на", "") ?? "";
|
||||
globalThis.document.execCommand("insertText", false, replacement);
|
||||
updateHtml();
|
||||
}
|
||||
|
||||
function insertLink() {
|
||||
const href = normalizedLinkInput(window.prompt("Введите адрес ссылки"));
|
||||
if (!href) {
|
||||
@@ -274,7 +354,7 @@ export function QWord({ document, onChange }: QWordProps) {
|
||||
return (
|
||||
<div className="editor-layout qword-layout">
|
||||
<section className="document-stage" aria-label="Редактор QWord">
|
||||
<div className="module-toolbar">
|
||||
<div className="module-toolbar word-module-toolbar">
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
className="hidden-file-input"
|
||||
@@ -291,104 +371,192 @@ export function QWord({ document, onChange }: QWordProps) {
|
||||
onChange={(event) => void insertImage(event.target.files?.[0])}
|
||||
aria-label="Вставить изображение"
|
||||
/>
|
||||
<input
|
||||
className="file-title-input"
|
||||
value={document.title}
|
||||
aria-label="Название документа"
|
||||
onChange={(event) => onChange({ ...document, title: event.target.value })}
|
||||
/>
|
||||
<div className="segmented-tools" aria-label="Форматирование текста">
|
||||
<button type="button" onClick={() => runCommand("bold")} title="Полужирный">
|
||||
<Bold size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("italic")} title="Курсив">
|
||||
<Italic size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("underline")} title="Подчеркнутый">
|
||||
<Underline size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("strikeThrough")} title="Зачеркнутый" aria-label="Зачеркнутый">
|
||||
<Strikethrough size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("insertUnorderedList")} title="Маркированный список">
|
||||
<List size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={insertLink} title="Вставить ссылку">
|
||||
<Link size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={insertPageBreak} title="Разрыв страницы" aria-label="Разрыв страницы">
|
||||
<SeparatorHorizontal size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => imageInputRef.current?.click()} title="Вставить изображение">
|
||||
<ImageIcon size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("justifyLeft")} title="По левому краю">
|
||||
<AlignLeft size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("justifyCenter")} title="По центру">
|
||||
<AlignCenter size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("justifyRight")} title="По правому краю">
|
||||
<AlignRight size={16} />
|
||||
</button>
|
||||
<div className="word-ribbon" aria-label="Лента команд QWord">
|
||||
<section className="word-ribbon-group word-file-group" aria-label="Файл">
|
||||
<div className="word-file-actions">
|
||||
<button className="word-icon-command" type="button" onClick={() => void chooseDocx()} title="Открыть" aria-label="Открыть">
|
||||
<FileUp size={16} />
|
||||
</button>
|
||||
<button className="word-icon-command" type="button" onClick={() => void saveDocx()} title="Сохранить" aria-label="Сохранить">
|
||||
<Save size={16} />
|
||||
</button>
|
||||
<button
|
||||
className="word-icon-command"
|
||||
type="button"
|
||||
onClick={() => downloadTextFile(document.title.replace(/\.qdocx$/i, ".html"), document.html, "text/html")}
|
||||
title="Сохранить как HTML"
|
||||
aria-label="Сохранить как HTML"
|
||||
>
|
||||
<Download size={16} />
|
||||
</button>
|
||||
<button className="word-icon-command" type="button" onClick={() => void exportPdf()} title="Экспорт PDF" aria-label="Экспорт PDF">
|
||||
<FileText size={16} />
|
||||
</button>
|
||||
</div>
|
||||
<span className="word-ribbon-title">Файл</span>
|
||||
</section>
|
||||
|
||||
<section className="word-ribbon-group word-clipboard-group" aria-label="Буфер обмена">
|
||||
<button className="word-large-command" type="button" onClick={() => runCommand("paste")} title="Вставить">
|
||||
<ClipboardPaste size={22} />
|
||||
<span>Вставить</span>
|
||||
</button>
|
||||
<div className="word-command-stack">
|
||||
<button type="button" onClick={() => runCommand("cut")} title="Вырезать">
|
||||
<Scissors size={15} />
|
||||
Вырезать
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("copy")} title="Копировать">
|
||||
<Copy size={15} />
|
||||
Копировать
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("removeFormat")} title="Очистить формат">
|
||||
<RemoveFormatting size={15} />
|
||||
Очистить
|
||||
</button>
|
||||
</div>
|
||||
<span className="word-ribbon-title">Буфер обмена</span>
|
||||
</section>
|
||||
|
||||
<section className="word-ribbon-group word-font-group" aria-label="Шрифт">
|
||||
<div className="word-select-row">
|
||||
<select className="word-font-select" aria-label="Шрифт" defaultValue="Calibri" onChange={(event) => applyFontFamily(event.target.value)}>
|
||||
{fontFamilyOptions.map((fontFamily) => (
|
||||
<option key={fontFamily} value={fontFamily}>
|
||||
{fontFamily}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<select className="word-font-size-select" aria-label="Размер шрифта" defaultValue="11" onChange={(event) => applyFontSize(event.target.value)}>
|
||||
{fontSizeOptions.map((fontSize) => (
|
||||
<option key={fontSize} value={fontSize}>
|
||||
{fontSize}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="segmented-tools word-format-tools" aria-label="Форматирование текста">
|
||||
<button type="button" onClick={() => runCommand("bold")} title="Полужирный">
|
||||
<Bold size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("italic")} title="Курсив">
|
||||
<Italic size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("underline")} title="Подчеркнутый">
|
||||
<Underline size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("strikeThrough")} title="Зачеркнутый" aria-label="Зачеркнутый">
|
||||
<Strikethrough size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("subscript")} title="Нижний индекс">
|
||||
<Subscript size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("superscript")} title="Верхний индекс">
|
||||
<Superscript size={16} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="word-color-row">
|
||||
<div className="text-color-tools" aria-label="Цвет текста">
|
||||
<Type size={16} aria-hidden="true" />
|
||||
{textColorSwatches.map((swatch) => (
|
||||
<button
|
||||
key={swatch.label}
|
||||
className="color-swatch"
|
||||
type="button"
|
||||
onClick={() => applyTextColor(swatch.color)}
|
||||
title={swatch.label}
|
||||
aria-label={swatch.label}
|
||||
style={{ backgroundColor: swatch.color }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="text-color-tools" aria-label="Подсветка текста">
|
||||
<PaintBucket size={16} aria-hidden="true" />
|
||||
{highlightSwatches.map((swatch) => (
|
||||
<button
|
||||
key={swatch.label}
|
||||
className="color-swatch"
|
||||
type="button"
|
||||
onClick={() => applyHighlight(swatch.color)}
|
||||
title={swatch.label}
|
||||
aria-label={swatch.label}
|
||||
style={{ backgroundColor: swatch.color }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<span className="word-ribbon-title">Шрифт</span>
|
||||
</section>
|
||||
|
||||
<section className="word-ribbon-group word-paragraph-group" aria-label="Абзац">
|
||||
<div className="segmented-tools" aria-label="Списки">
|
||||
<button type="button" onClick={() => runCommand("insertUnorderedList")} title="Маркированный список">
|
||||
<List size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("insertOrderedList")} title="Нумерованный список">
|
||||
<ListOrdered size={16} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="segmented-tools" aria-label="Выравнивание">
|
||||
<button type="button" onClick={() => runCommand("justifyLeft")} title="По левому краю">
|
||||
<AlignLeft size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("justifyCenter")} title="По центру">
|
||||
<AlignCenter size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("justifyRight")} title="По правому краю">
|
||||
<AlignRight size={16} />
|
||||
</button>
|
||||
<button type="button" onClick={() => runCommand("justifyFull")} title="По ширине">
|
||||
<AlignJustify size={16} />
|
||||
</button>
|
||||
</div>
|
||||
<button className="compact-command" type="button" onClick={insertPageBreak} title="Разрыв страницы" aria-label="Разрыв страницы">
|
||||
<SeparatorHorizontal size={16} />
|
||||
Разрыв
|
||||
</button>
|
||||
<span className="word-ribbon-title">Абзац</span>
|
||||
</section>
|
||||
|
||||
<section className="word-ribbon-group word-styles-group" aria-label="Стили">
|
||||
<div className="word-style-gallery">
|
||||
{styleGalleryOptions.map((style) => (
|
||||
<button key={style.value} type="button" onClick={() => runCommand("formatBlock", style.value)}>
|
||||
<span>AaБбВв</span>
|
||||
{style.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<span className="word-ribbon-title">Стили</span>
|
||||
</section>
|
||||
|
||||
<section className="word-ribbon-group word-insert-group" aria-label="Вставка">
|
||||
<button className="compact-command" type="button" onClick={insertLink}>
|
||||
<Link size={16} />
|
||||
Ссылка
|
||||
</button>
|
||||
<button className="compact-command" type="button" onClick={() => imageInputRef.current?.click()}>
|
||||
<ImageIcon size={16} />
|
||||
Рисунок
|
||||
</button>
|
||||
<span className="word-ribbon-title">Вставка</span>
|
||||
</section>
|
||||
|
||||
<section className="word-ribbon-group word-edit-group" aria-label="Редактирование">
|
||||
<button className="compact-command" type="button" onClick={findText}>
|
||||
<Search size={16} />
|
||||
Найти
|
||||
</button>
|
||||
<button className="compact-command" type="button" onClick={replaceText}>
|
||||
<Replace size={16} />
|
||||
Заменить
|
||||
</button>
|
||||
<span className="toolbar-status">
|
||||
Страниц: {pageView.count} · Слов: {wordCount}
|
||||
</span>
|
||||
<span className="word-ribbon-title">Редактирование</span>
|
||||
</section>
|
||||
</div>
|
||||
<div className="text-color-tools" aria-label="Цвет текста">
|
||||
<Type size={16} aria-hidden="true" />
|
||||
{textColorSwatches.map((swatch) => (
|
||||
<button
|
||||
key={swatch.label}
|
||||
className="color-swatch"
|
||||
type="button"
|
||||
onClick={() => applyTextColor(swatch.color)}
|
||||
title={swatch.label}
|
||||
aria-label={swatch.label}
|
||||
style={{ backgroundColor: swatch.color }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="text-color-tools" aria-label="Подсветка текста">
|
||||
<PaintBucket size={16} aria-hidden="true" />
|
||||
{highlightSwatches.map((swatch) => (
|
||||
<button
|
||||
key={swatch.label}
|
||||
className="color-swatch"
|
||||
type="button"
|
||||
onClick={() => applyHighlight(swatch.color)}
|
||||
title={swatch.label}
|
||||
aria-label={swatch.label}
|
||||
style={{ backgroundColor: swatch.color }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<select aria-label="Стиль абзаца" onChange={(event) => runCommand("formatBlock", event.target.value)}>
|
||||
<option value="p">Обычный текст</option>
|
||||
<option value="h1">Заголовок 1</option>
|
||||
<option value="h2">Заголовок 2</option>
|
||||
<option value="blockquote">Цитата</option>
|
||||
</select>
|
||||
<button className="compact-command" type="button" onClick={() => void chooseDocx()}>
|
||||
<FileUp size={16} />
|
||||
Открыть DOCX
|
||||
</button>
|
||||
<button className="compact-command" type="button" onClick={() => void saveDocx()}>
|
||||
<Save size={16} />
|
||||
Сохранить DOCX
|
||||
</button>
|
||||
<button
|
||||
className="compact-command"
|
||||
type="button"
|
||||
onClick={() => downloadTextFile(document.title.replace(/\.qdocx$/i, ".html"), document.html, "text/html")}
|
||||
>
|
||||
<Download size={16} />
|
||||
Экспорт HTML
|
||||
</button>
|
||||
<button className="compact-command" type="button" onClick={() => void exportPdf()}>
|
||||
<FileText size={16} />
|
||||
Экспорт PDF
|
||||
</button>
|
||||
<span className="toolbar-status">
|
||||
Страниц: {pageView.count} · Слов: {wordCount}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="page-ruler" aria-hidden="true">
|
||||
|
||||
+236
@@ -327,6 +327,242 @@ button {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
}
|
||||
|
||||
.word-module-toolbar {
|
||||
display: block;
|
||||
min-height: 118px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.word-ribbon {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
min-height: 118px;
|
||||
overflow: hidden;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.word-ribbon-group {
|
||||
display: grid;
|
||||
grid-template-rows: minmax(0, 1fr) 18px;
|
||||
align-items: stretch;
|
||||
gap: 4px;
|
||||
min-height: 118px;
|
||||
min-width: 0;
|
||||
padding: 8px 10px 4px;
|
||||
border-right: 1px solid #d6dde8;
|
||||
}
|
||||
|
||||
.word-ribbon-title {
|
||||
align-self: end;
|
||||
color: #69778a;
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.word-command-row,
|
||||
.word-select-row,
|
||||
.word-color-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.word-file-group {
|
||||
flex: 0 0 76px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.word-file-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 28px);
|
||||
align-content: start;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.word-icon-command {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.word-icon-command:hover {
|
||||
border-color: #c7d8eb;
|
||||
background: #edf6ff;
|
||||
}
|
||||
|
||||
.word-clipboard-group {
|
||||
flex: 0 0 150px;
|
||||
grid-template-columns: auto auto;
|
||||
}
|
||||
|
||||
.word-clipboard-group .word-ribbon-title,
|
||||
.word-font-group .word-ribbon-title,
|
||||
.word-paragraph-group .word-ribbon-title,
|
||||
.word-styles-group .word-ribbon-title,
|
||||
.word-insert-group .word-ribbon-title,
|
||||
.word-edit-group .word-ribbon-title {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.word-large-command {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
align-content: center;
|
||||
gap: 4px;
|
||||
min-width: 66px;
|
||||
min-height: 70px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.word-large-command:hover,
|
||||
.word-command-stack button:hover,
|
||||
.word-style-gallery button:hover {
|
||||
border-color: #c7d8eb;
|
||||
background: #edf6ff;
|
||||
}
|
||||
|
||||
.word-command-stack {
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.word-command-stack button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-height: 22px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.word-font-group {
|
||||
flex: 1 1 266px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.word-font-select {
|
||||
min-width: 0;
|
||||
flex: 1 1 170px;
|
||||
}
|
||||
|
||||
.word-font-size-select {
|
||||
flex: 0 0 64px;
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.word-format-tools {
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.word-color-row {
|
||||
flex-wrap: wrap;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.word-color-row .text-color-tools {
|
||||
min-height: 26px;
|
||||
padding-left: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.word-color-row .color-swatch {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.word-paragraph-group {
|
||||
flex: 0 0 170px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.word-paragraph-group > .segmented-tools,
|
||||
.word-paragraph-group > .compact-command {
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.word-paragraph-group .compact-command {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.word-styles-group {
|
||||
flex: 0 1 210px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.word-style-gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(74px, 1fr));
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.word-style-gallery button {
|
||||
display: grid;
|
||||
align-content: center;
|
||||
min-height: 64px;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid #d6dde8;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
color: #334155;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.word-style-gallery button span {
|
||||
color: #1e5fa7;
|
||||
font-size: 20px;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.word-insert-group {
|
||||
flex: 0 0 96px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.word-insert-group .compact-command,
|
||||
.word-edit-group .compact-command {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.word-edit-group {
|
||||
flex: 0 0 132px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.word-edit-group .toolbar-status {
|
||||
min-height: 26px;
|
||||
padding: 0;
|
||||
border-left: 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.hidden-file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user