Добавлены новые настройки пользователя: возможность отображения даты редактирования и использования цветных иконок. Обновлены соответствующие компоненты и стили для поддержки новых функций. Реализована логика добавления колонок в базу данных при отсутствии. Обновлены API и интерфейсы для работы с новыми параметрами.
This commit is contained in:
parent
143338bc2b
commit
8c3db305ca
@ -464,6 +464,42 @@ function runMigrations() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверяем существование колонки show_edit_date
|
||||||
|
const hasShowEditDate = columns.some((col) => col.name === "show_edit_date");
|
||||||
|
if (!hasShowEditDate) {
|
||||||
|
db.run(
|
||||||
|
"ALTER TABLE users ADD COLUMN show_edit_date INTEGER DEFAULT 1",
|
||||||
|
(err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(
|
||||||
|
"Ошибка добавления колонки show_edit_date:",
|
||||||
|
err.message
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log("Колонка show_edit_date добавлена в таблицу users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем существование колонки colored_icons
|
||||||
|
const hasColoredIcons = columns.some((col) => col.name === "colored_icons");
|
||||||
|
if (!hasColoredIcons) {
|
||||||
|
db.run(
|
||||||
|
"ALTER TABLE users ADD COLUMN colored_icons INTEGER DEFAULT 1",
|
||||||
|
(err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(
|
||||||
|
"Ошибка добавления колонки colored_icons:",
|
||||||
|
err.message
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log("Колонка colored_icons добавлена в таблицу users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Проверяем существование колонки ai_enabled
|
// Проверяем существование колонки ai_enabled
|
||||||
const hasAiEnabled = columns.some((col) => col.name === "ai_enabled");
|
const hasAiEnabled = columns.some((col) => col.name === "ai_enabled");
|
||||||
if (!hasAiEnabled) {
|
if (!hasAiEnabled) {
|
||||||
@ -733,7 +769,7 @@ app.get("/api/user", requireApiAuth, (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sql =
|
const sql =
|
||||||
"SELECT username, email, avatar, accent_color FROM users WHERE id = ?";
|
"SELECT username, email, avatar, accent_color, show_edit_date, colored_icons FROM users WHERE id = ?";
|
||||||
db.get(sql, [req.session.userId], (err, user) => {
|
db.get(sql, [req.session.userId], (err, user) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Ошибка получения данных пользователя:", err.message);
|
console.error("Ошибка получения данных пользователя:", err.message);
|
||||||
@ -1528,7 +1564,7 @@ app.get("/profile", requireAuth, (req, res) => {
|
|||||||
|
|
||||||
// API для обновления профиля
|
// API для обновления профиля
|
||||||
app.put("/api/user/profile", requireApiAuth, async (req, res) => {
|
app.put("/api/user/profile", requireApiAuth, async (req, res) => {
|
||||||
const { username, email, currentPassword, newPassword, accent_color } =
|
const { username, email, currentPassword, newPassword, accent_color, show_edit_date, colored_icons } =
|
||||||
req.body;
|
req.body;
|
||||||
const userId = req.session.userId;
|
const userId = req.session.userId;
|
||||||
|
|
||||||
@ -1594,6 +1630,16 @@ app.put("/api/user/profile", requireApiAuth, async (req, res) => {
|
|||||||
params.push(accent_color || "#007bff");
|
params.push(accent_color || "#007bff");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (show_edit_date !== undefined) {
|
||||||
|
updateFields.push("show_edit_date = ?");
|
||||||
|
params.push(show_edit_date ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colored_icons !== undefined) {
|
||||||
|
updateFields.push("colored_icons = ?");
|
||||||
|
params.push(colored_icons ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (newPassword) {
|
if (newPassword) {
|
||||||
const hashedPassword = await bcrypt.hash(newPassword, 10);
|
const hashedPassword = await bcrypt.hash(newPassword, 10);
|
||||||
updateFields.push("password = ?");
|
updateFields.push("password = ?");
|
||||||
@ -1628,6 +1674,8 @@ app.put("/api/user/profile", requireApiAuth, async (req, res) => {
|
|||||||
if (username && username !== user.username) changes.push("логин");
|
if (username && username !== user.username) changes.push("логин");
|
||||||
if (email !== undefined) changes.push("email");
|
if (email !== undefined) changes.push("email");
|
||||||
if (accent_color !== undefined) changes.push("цвет темы");
|
if (accent_color !== undefined) changes.push("цвет темы");
|
||||||
|
if (show_edit_date !== undefined) changes.push("настройка показа даты редактирования");
|
||||||
|
if (colored_icons !== undefined) changes.push("цветные иконки");
|
||||||
if (newPassword) changes.push("пароль");
|
if (newPassword) changes.push("пароль");
|
||||||
const details = `Обновлен профиль: ${changes.join(", ")}`;
|
const details = `Обновлен профиль: ${changes.join(", ")}`;
|
||||||
logAction(userId, "profile_update", details);
|
logAction(userId, "profile_update", details);
|
||||||
|
|||||||
@ -85,7 +85,7 @@ define(['./workbox-8cfb3eb5'], (function (workbox) { 'use strict';
|
|||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.tihabijh3s"
|
"revision": "0.8irmmrfvp3g"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|||||||
@ -12,6 +12,8 @@ export const userApi = {
|
|||||||
currentPassword?: string;
|
currentPassword?: string;
|
||||||
newPassword?: string;
|
newPassword?: string;
|
||||||
accent_color?: string;
|
accent_color?: string;
|
||||||
|
show_edit_date?: boolean;
|
||||||
|
colored_icons?: boolean;
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
const { data } = await axiosClient.put("/user/profile", profile);
|
const { data } = await axiosClient.put("/user/profile", profile);
|
||||||
|
|||||||
@ -43,6 +43,14 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
dispatch(setAccentColorAction(accent));
|
dispatch(setAccentColorAction(accent));
|
||||||
setAccentColor(accent);
|
setAccentColor(accent);
|
||||||
|
|
||||||
|
// Применяем настройку цветных иконок
|
||||||
|
const coloredIcons = userData.colored_icons !== undefined ? userData.colored_icons === 1 : true;
|
||||||
|
if (coloredIcons) {
|
||||||
|
document.body.classList.add("colored-icons");
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove("colored-icons");
|
||||||
|
}
|
||||||
|
|
||||||
// Загружаем AI настройки
|
// Загружаем AI настройки
|
||||||
try {
|
try {
|
||||||
const aiSettings = await userApi.getAiSettings();
|
const aiSettings = await userApi.getAiSettings();
|
||||||
|
|||||||
@ -62,6 +62,7 @@ export const NoteItem: React.FC<NoteItemProps> = ({
|
|||||||
const searchQuery = useAppSelector((state) => state.notes.searchQuery);
|
const searchQuery = useAppSelector((state) => state.notes.searchQuery);
|
||||||
const isPreviewMode = useAppSelector((state) => state.ui.isPreviewMode);
|
const isPreviewMode = useAppSelector((state) => state.ui.isPreviewMode);
|
||||||
const aiEnabled = useAppSelector((state) => state.profile.aiEnabled);
|
const aiEnabled = useAppSelector((state) => state.profile.aiEnabled);
|
||||||
|
const user = useAppSelector((state) => state.profile.user);
|
||||||
const { showNotification } = useNotification();
|
const { showNotification } = useNotification();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
useMarkdown({ onNoteUpdate: onReload }); // Инициализируем обработчики спойлеров, внешних ссылок и чекбоксов
|
useMarkdown({ onNoteUpdate: onReload }); // Инициализируем обработчики спойлеров, внешних ссылок и чекбоксов
|
||||||
@ -914,6 +915,7 @@ export const NoteItem: React.FC<NoteItemProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (note.updated_at && note.created_at !== note.updated_at) {
|
if (note.updated_at && note.created_at !== note.updated_at) {
|
||||||
|
const showEditDate = user?.show_edit_date !== undefined ? user.show_edit_date === 1 : true;
|
||||||
const updated = parseSQLiteUtc(note.updated_at);
|
const updated = parseSQLiteUtc(note.updated_at);
|
||||||
const updatedStr = formatLocalDateTime(updated);
|
const updatedStr = formatLocalDateTime(updated);
|
||||||
// Убеждаемся, что строка не содержит лишних символов
|
// Убеждаемся, что строка не содержит лишних символов
|
||||||
@ -921,17 +923,30 @@ export const NoteItem: React.FC<NoteItemProps> = ({
|
|||||||
/(\d{2}\.\d{2}\.\d{4} \d{2}:\d{2})\d*.*/,
|
/(\d{2}\.\d{2}\.\d{4} \d{2}:\d{2})\d*.*/,
|
||||||
"$1"
|
"$1"
|
||||||
);
|
);
|
||||||
return (
|
|
||||||
<>
|
if (showEditDate) {
|
||||||
{cleanCreatedStr}
|
return (
|
||||||
<span className="date-separator"> | </span>
|
<>
|
||||||
<Icon
|
{cleanCreatedStr}
|
||||||
icon="mdi:pencil"
|
<span className="date-separator"> | </span>
|
||||||
style={{ fontSize: "12px", margin: "0 2px" }}
|
<Icon
|
||||||
/>
|
icon="mdi:pencil"
|
||||||
{cleanUpdatedStr}
|
style={{ fontSize: "12px", margin: "0 2px" }}
|
||||||
</>
|
/>
|
||||||
);
|
{cleanUpdatedStr}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{cleanCreatedStr}
|
||||||
|
<Icon
|
||||||
|
icon="mdi:pencil"
|
||||||
|
style={{ fontSize: "12px", margin: "0 2px" }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return cleanCreatedStr;
|
return cleanCreatedStr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,8 @@ const SettingsPage: React.FC = () => {
|
|||||||
|
|
||||||
// Appearance settings
|
// Appearance settings
|
||||||
const [selectedAccentColor, setSelectedAccentColor] = useState("#007bff");
|
const [selectedAccentColor, setSelectedAccentColor] = useState("#007bff");
|
||||||
|
const [showEditDate, setShowEditDate] = useState(true);
|
||||||
|
const [coloredIcons, setColoredIcons] = useState(true);
|
||||||
|
|
||||||
// AI settings
|
// AI settings
|
||||||
const [apiKey, setApiKey] = useState("");
|
const [apiKey, setApiKey] = useState("");
|
||||||
@ -84,6 +86,10 @@ const SettingsPage: React.FC = () => {
|
|||||||
setSelectedAccentColor(accent);
|
setSelectedAccentColor(accent);
|
||||||
dispatch(setAccentColorAction(accent));
|
dispatch(setAccentColorAction(accent));
|
||||||
setAccentColor(accent);
|
setAccentColor(accent);
|
||||||
|
setShowEditDate(userData.show_edit_date !== undefined ? userData.show_edit_date === 1 : true);
|
||||||
|
const coloredIconsValue = userData.colored_icons !== undefined ? userData.colored_icons === 1 : true;
|
||||||
|
setColoredIcons(coloredIconsValue);
|
||||||
|
updateColoredIconsClass(coloredIconsValue);
|
||||||
|
|
||||||
// Загружаем AI настройки
|
// Загружаем AI настройки
|
||||||
try {
|
try {
|
||||||
@ -114,13 +120,17 @@ const SettingsPage: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
await userApi.updateProfile({
|
await userApi.updateProfile({
|
||||||
accent_color: selectedAccentColor,
|
accent_color: selectedAccentColor,
|
||||||
|
show_edit_date: showEditDate,
|
||||||
|
colored_icons: coloredIcons,
|
||||||
});
|
});
|
||||||
dispatch(setAccentColorAction(selectedAccentColor));
|
dispatch(setAccentColorAction(selectedAccentColor));
|
||||||
setAccentColor(selectedAccentColor);
|
setAccentColor(selectedAccentColor);
|
||||||
await loadUserInfo();
|
await loadUserInfo();
|
||||||
showNotification("Цветовой акцент успешно обновлен", "success");
|
// Обновляем класс на body для управления цветными иконками
|
||||||
|
updateColoredIconsClass(coloredIcons);
|
||||||
|
showNotification("Настройки внешнего вида успешно обновлены", "success");
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("Ошибка обновления цветового акцента:", error);
|
console.error("Ошибка обновления настроек внешнего вида:", error);
|
||||||
showNotification(
|
showNotification(
|
||||||
error.response?.data?.error || "Ошибка обновления",
|
error.response?.data?.error || "Ошибка обновления",
|
||||||
"error"
|
"error"
|
||||||
@ -128,6 +138,14 @@ const SettingsPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateColoredIconsClass = (enabled: boolean) => {
|
||||||
|
if (enabled) {
|
||||||
|
document.body.classList.add("colored-icons");
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove("colored-icons");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleUpdateAiSettings = async () => {
|
const handleUpdateAiSettings = async () => {
|
||||||
if (!apiKey.trim()) {
|
if (!apiKey.trim()) {
|
||||||
showNotification("API ключ обязателен", "error");
|
showNotification("API ключ обязателен", "error");
|
||||||
@ -420,6 +438,55 @@ const SettingsPage: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group ai-toggle-group">
|
||||||
|
<label className="ai-toggle-label">
|
||||||
|
<div className="toggle-label-content">
|
||||||
|
<span className="toggle-text-main">Показывать дату редактирования</span>
|
||||||
|
<span className="toggle-text-desc">
|
||||||
|
{showEditDate
|
||||||
|
? "Отображать дату последнего редактирования заметки рядом с датой создания"
|
||||||
|
: "Показывать только иконку карандаша без даты редактирования"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="toggle-switch-wrapper">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="show-edit-date-toggle"
|
||||||
|
className="toggle-checkbox"
|
||||||
|
checked={showEditDate}
|
||||||
|
onChange={(e) => setShowEditDate(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span className="toggle-slider"></span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group ai-toggle-group">
|
||||||
|
<label className="ai-toggle-label">
|
||||||
|
<div className="toggle-label-content">
|
||||||
|
<span className="toggle-text-main">Цветные иконки</span>
|
||||||
|
<span className="toggle-text-desc">
|
||||||
|
{coloredIcons
|
||||||
|
? "Иконки отображаются разными цветами для лучшей визуальной дифференциации"
|
||||||
|
: "Все иконки отображаются в монохромном стиле"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="toggle-switch-wrapper">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="colored-icons-toggle"
|
||||||
|
className="toggle-checkbox"
|
||||||
|
checked={coloredIcons}
|
||||||
|
onChange={(e) => {
|
||||||
|
setColoredIcons(e.target.checked);
|
||||||
|
updateColoredIconsClass(e.target.checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span className="toggle-slider"></span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button className="btnSave" onClick={handleUpdateAppearance}>
|
<button className="btnSave" onClick={handleUpdateAppearance}>
|
||||||
Сохранить изменения
|
Сохранить изменения
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -179,26 +179,178 @@ header .iconify {
|
|||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Цветные иконки */
|
/* Цветные иконки - для кнопок заметок и заголовков страниц */
|
||||||
/* Иконка поиска - синий */
|
.colored-icons .iconify svg,
|
||||||
.search-title .iconify[data-icon="mdi:magnify"] {
|
.colored-icons iconify-icon svg {
|
||||||
color: var(--icon-search);
|
fill: currentColor !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Иконка тегов - зеленый */
|
/* Универсальное правило для всех SVG в заголовках */
|
||||||
.tags-title .iconify[data-icon="mdi:tag"] {
|
.colored-icons header svg,
|
||||||
color: var(--icon-tags);
|
.colored-icons header img[role="img"] svg {
|
||||||
|
fill: currentColor !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Иконка заметок - оранжевый */
|
/* Иконки в заголовках страниц */
|
||||||
header .iconify[data-icon="mdi:note-text"] {
|
/* Мои заметки - оранжевый */
|
||||||
color: var(--icon-notes);
|
.colored-icons .notes-header-left .iconify,
|
||||||
|
.colored-icons .notes-header-left iconify-icon,
|
||||||
|
.colored-icons header .notes-header-left .iconify,
|
||||||
|
.colored-icons header .notes-header-left iconify-icon,
|
||||||
|
.colored-icons header .notes-header-left svg,
|
||||||
|
.colored-icons header .notes-header span .iconify,
|
||||||
|
.colored-icons header .notes-header span iconify-icon,
|
||||||
|
.colored-icons header .notes-header span svg,
|
||||||
|
.colored-icons .notes-header-left img[src*="data:image/svg"],
|
||||||
|
.colored-icons header .notes-header-left img[src*="data:image/svg"],
|
||||||
|
.colored-icons header .notes-header span img[src*="data:image/svg"] {
|
||||||
|
color: #ff9800 !important;
|
||||||
|
fill: #ff9800 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Иконка пользователя - фиолетовый */
|
.colored-icons .notes-header-left svg,
|
||||||
header .iconify[data-icon="mdi:account"],
|
.colored-icons header .notes-header-left svg,
|
||||||
.username-clickable .iconify[data-icon="mdi:account"] {
|
.colored-icons header .notes-header span svg,
|
||||||
color: var(--icon-user);
|
.colored-icons .notes-header-left img svg,
|
||||||
|
.colored-icons header .notes-header-left img svg {
|
||||||
|
fill: #ff9800 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Все SVG внутри notes-header-left */
|
||||||
|
.colored-icons .notes-header-left svg path,
|
||||||
|
.colored-icons header .notes-header-left svg path {
|
||||||
|
fill: #ff9800 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Настройки - серый/синий */
|
||||||
|
.colored-icons .settings-icon-btn .iconify,
|
||||||
|
.colored-icons .settings-icon-btn iconify-icon,
|
||||||
|
.colored-icons header button.settings-icon-btn .iconify,
|
||||||
|
.colored-icons header button.settings-icon-btn iconify-icon,
|
||||||
|
.colored-icons .settings-icon-btn svg,
|
||||||
|
.colored-icons header button.settings-icon-btn svg,
|
||||||
|
.colored-icons .settings-icon-btn svg path,
|
||||||
|
.colored-icons header button.settings-icon-btn svg path {
|
||||||
|
color: #607d8b !important;
|
||||||
|
fill: #607d8b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Профиль - фиолетовый */
|
||||||
|
.colored-icons .user-avatar-placeholder-mini .iconify,
|
||||||
|
.colored-icons .user-avatar-placeholder-mini iconify-icon,
|
||||||
|
.colored-icons header .user-avatar-placeholder-mini .iconify,
|
||||||
|
.colored-icons header .user-avatar-placeholder-mini iconify-icon,
|
||||||
|
.colored-icons .user-avatar-placeholder-mini svg,
|
||||||
|
.colored-icons header .user-avatar-placeholder-mini svg,
|
||||||
|
.colored-icons .user-avatar-placeholder-mini svg path,
|
||||||
|
.colored-icons header .user-avatar-placeholder-mini svg path {
|
||||||
|
color: #9c27b0 !important;
|
||||||
|
fill: #9c27b0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Выйти - красный */
|
||||||
|
.colored-icons .logout-btn .iconify,
|
||||||
|
.colored-icons .logout-btn iconify-icon,
|
||||||
|
.colored-icons header button.logout-btn .iconify,
|
||||||
|
.colored-icons header button.logout-btn iconify-icon,
|
||||||
|
.colored-icons .logout-btn svg,
|
||||||
|
.colored-icons header button.logout-btn svg,
|
||||||
|
.colored-icons .logout-btn svg path,
|
||||||
|
.colored-icons header button.logout-btn svg path {
|
||||||
|
color: #f44336 !important;
|
||||||
|
fill: #f44336 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Вход - синий */
|
||||||
|
.colored-icons header .iconify[data-icon="mdi:login"],
|
||||||
|
.colored-icons header iconify-icon[icon="mdi:login"] {
|
||||||
|
color: #2196f3 !important;
|
||||||
|
fill: #2196f3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Регистрация - зеленый */
|
||||||
|
.colored-icons header .iconify[data-icon="mdi:account-plus"],
|
||||||
|
.colored-icons header iconify-icon[icon="mdi:account-plus"] {
|
||||||
|
color: #4caf50 !important;
|
||||||
|
fill: #4caf50 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Заголовок Настройки - серый/синий */
|
||||||
|
.colored-icons header.notes-header span:first-child .iconify,
|
||||||
|
.colored-icons header.notes-header span:first-child iconify-icon,
|
||||||
|
.colored-icons header.notes-header span:first-child svg,
|
||||||
|
.colored-icons header.notes-header span:first-child svg path {
|
||||||
|
color: #607d8b !important;
|
||||||
|
fill: #607d8b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Кнопки в заголовке настроек */
|
||||||
|
.colored-icons header .notes-btn .iconify,
|
||||||
|
.colored-icons header .notes-btn iconify-icon,
|
||||||
|
.colored-icons header button.notes-btn .iconify,
|
||||||
|
.colored-icons header button.notes-btn iconify-icon,
|
||||||
|
.colored-icons header .notes-btn svg,
|
||||||
|
.colored-icons header button.notes-btn svg,
|
||||||
|
.colored-icons header .notes-btn svg path,
|
||||||
|
.colored-icons header button.notes-btn svg path {
|
||||||
|
color: #ff9800 !important;
|
||||||
|
fill: #ff9800 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colored-icons header .profile-btn .iconify,
|
||||||
|
.colored-icons header .profile-btn iconify-icon,
|
||||||
|
.colored-icons header button.profile-btn .iconify,
|
||||||
|
.colored-icons header button.profile-btn iconify-icon,
|
||||||
|
.colored-icons header .profile-btn svg,
|
||||||
|
.colored-icons header button.profile-btn svg,
|
||||||
|
.colored-icons header .profile-btn svg path,
|
||||||
|
.colored-icons header button.profile-btn svg path {
|
||||||
|
color: #9c27b0 !important;
|
||||||
|
fill: #9c27b0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Табы в настройках */
|
||||||
|
.colored-icons .settings-tab .iconify[data-icon="mdi:palette"],
|
||||||
|
.colored-icons .settings-tab iconify-icon[icon="mdi:palette"] {
|
||||||
|
color: #e91e63 !important;
|
||||||
|
fill: #e91e63 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colored-icons .settings-tab .iconify[data-icon="mdi:robot"],
|
||||||
|
.colored-icons .settings-tab iconify-icon[icon="mdi:robot"] {
|
||||||
|
color: #ff6f00 !important;
|
||||||
|
fill: #ff6f00 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colored-icons .settings-tab .iconify[data-icon="mdi:archive"],
|
||||||
|
.colored-icons .settings-tab iconify-icon[icon="mdi:archive"] {
|
||||||
|
color: #ff9800 !important;
|
||||||
|
fill: #ff9800 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colored-icons .settings-tab .iconify[data-icon="mdi:history"],
|
||||||
|
.colored-icons .settings-tab iconify-icon[icon="mdi:history"] {
|
||||||
|
color: #9c27b0 !important;
|
||||||
|
fill: #9c27b0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Иконки кнопок заметок - цветные при включенной настройке */
|
||||||
|
.colored-icons .note-actions .notesHeaderBtn:nth-child(1) .iconify,
|
||||||
|
.colored-icons .note-actions .notesHeaderBtn:nth-child(1) iconify-icon {
|
||||||
|
color: #ff9800 !important;
|
||||||
|
fill: #ff9800 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colored-icons .note-actions .notesHeaderBtn:nth-child(2) .iconify,
|
||||||
|
.colored-icons .note-actions .notesHeaderBtn:nth-child(2) iconify-icon {
|
||||||
|
color: #2196f3 !important;
|
||||||
|
fill: #2196f3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colored-icons .note-actions .notesHeaderBtn:nth-child(3) .iconify,
|
||||||
|
.colored-icons .note-actions .notesHeaderBtn:nth-child(3) iconify-icon {
|
||||||
|
color: #dc3545 !important;
|
||||||
|
fill: #dc3545 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Переключатель темы */
|
/* Переключатель темы */
|
||||||
@ -235,97 +387,6 @@ header .iconify[data-icon="mdi:account"],
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Иконка входа - синий */
|
|
||||||
header .iconify[data-icon="mdi:login"] {
|
|
||||||
color: #2196f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Иконка регистрации - зеленый */
|
|
||||||
header .iconify[data-icon="mdi:account-plus"] {
|
|
||||||
color: #4caf50;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown кнопки - разные цвета */
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:format-bold"] {
|
|
||||||
color: #d32f2f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:format-italic"] {
|
|
||||||
color: #f57c00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:palette"] {
|
|
||||||
color: #e91e63;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:format-header-1"] {
|
|
||||||
color: #1976d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:format-header-pound"] {
|
|
||||||
color: #1976d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:format-list-bulleted"] {
|
|
||||||
color: #388e3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:format-quote-close"] {
|
|
||||||
color: #f57c00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:code-tags"] {
|
|
||||||
color: #7b1fa2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:link"] {
|
|
||||||
color: #0288d1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:format-strikethrough"] {
|
|
||||||
color: #ff6f00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:format-list-numbered"] {
|
|
||||||
color: #4caf50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:checkbox-marked-outline"] {
|
|
||||||
color: #ff9800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:image-plus"] {
|
|
||||||
color: #2196f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:eye"] {
|
|
||||||
color: #607d8b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:file-plus"] {
|
|
||||||
color: #9c27b0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:eye-off"] {
|
|
||||||
color: #e91e63;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:robot"] {
|
|
||||||
color: #ff6f00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnMarkdown .iconify[data-icon="mdi:menu-down"] {
|
|
||||||
color: #1976d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notesHeaderBtn .iconify[data-icon="mdi:pencil"] {
|
|
||||||
color: #2196f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notesHeaderBtn .iconify[data-icon="mdi:delete"] {
|
|
||||||
color: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
header {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -1534,18 +1595,33 @@ textarea:focus {
|
|||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.floating-toolbar-btn .iconify[data-icon="mdi:format-bold"] {
|
.colored-icons .floating-toolbar-btn .iconify[data-icon="mdi:format-bold"],
|
||||||
|
.colored-icons .floating-toolbar-btn iconify-icon[icon="mdi:format-bold"] {
|
||||||
color: #1976d2;
|
color: #1976d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.floating-toolbar-btn .iconify[data-icon="mdi:format-italic"] {
|
.colored-icons .floating-toolbar-btn .iconify[data-icon="mdi:format-italic"],
|
||||||
|
.colored-icons .floating-toolbar-btn iconify-icon[icon="mdi:format-italic"] {
|
||||||
color: #7b1fa2;
|
color: #7b1fa2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.floating-toolbar-btn .iconify[data-icon="mdi:format-strikethrough"] {
|
.colored-icons
|
||||||
|
.floating-toolbar-btn
|
||||||
|
.iconify[data-icon="mdi:format-strikethrough"],
|
||||||
|
.colored-icons
|
||||||
|
.floating-toolbar-btn
|
||||||
|
iconify-icon[icon="mdi:format-strikethrough"] {
|
||||||
color: #ff6f00;
|
color: #ff6f00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Универсальный стиль для всех цветных иконок через SVG */
|
||||||
|
.colored-icons .iconify svg,
|
||||||
|
.colored-icons iconify-icon svg {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Монохромные иконки для плавающей панели уже покрыты универсальным селектором */
|
||||||
|
|
||||||
.floating-toolbar-btn.active {
|
.floating-toolbar-btn.active {
|
||||||
background-color: var(--bg-quaternary);
|
background-color: var(--bg-quaternary);
|
||||||
box-shadow: 0 0 0 2px var(--border-focus);
|
box-shadow: 0 0 0 2px var(--border-focus);
|
||||||
@ -4847,8 +4923,7 @@ textarea:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Очень маленькие экраны */
|
/* Очень маленькие экраны */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
|
||||||
.mobile-menu-btn .iconify {
|
.mobile-menu-btn .iconify {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ export interface User {
|
|||||||
email?: string;
|
email?: string;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
accent_color: string;
|
accent_color: string;
|
||||||
|
show_edit_date?: number;
|
||||||
|
colored_icons?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthResponse {
|
export interface AuthResponse {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user