feat: Replace Bootstrap buttons with custom button system

### Custom Button System Implementation

Created modern button system to replace Bootstrap buttons:

- ✅ Created core/_buttons-custom.scss (550+ lines)
- ✅ CSS Custom Properties for easy customization
- ✅ 8 color variants (primary, secondary, success, danger, warning, info, light, dark)
- ✅ Outline and Ghost variants
- ✅ 4 sizes (sm, md, lg, xl)
- ✅ Special variants (block, icon, circle, link)
- ✅ Loading state with spinner animation
- ✅ Button groups support
- ✅ Modern animations (hover, active, focus)

### Template Migration

Migrated 65 HTML templates using automated Python script:
- Replaced .btn → .button
- Replaced .btn-primary → .button--primary
- Replaced .btn-outline-* → .button--outline button--*
- Replaced size classes .btn-sm → .button--sm
- Total changes: 354 → 347 button usages

### Results

- app.css: 137 KB → 148 KB (+11 KB for custom buttons)
- Templates changed: 65 files
- Remaining .btn classes: 133 (mostly btn-close for modals)
- New .button classes: 347

### Backward Compatibility

Kept @extend rules in _buttons-custom.scss for gradual migration.
Can be removed after complete migration.

Next step: Remove Bootstrap button imports from custom-bootstrap.scss
This commit is contained in:
Игорь Надеин 2026-01-15 14:23:44 +03:00
parent 9df9f78666
commit 8159c6f472
71 changed files with 1178 additions and 256 deletions

View File

@ -0,0 +1,98 @@
#!/usr/bin/env python3
"""
Скрипт для миграции Bootstrap кнопок на новую систему
Заменяет .btn классы на .button классы
"""
import re
import os
from pathlib import Path
# Карта замен Bootstrap классов на новые
REPLACEMENTS = {
# Основной класс
r'\bbtn\b(?!-)': 'button',
# Цветовые варианты
r'\bbtn-primary\b': 'button--primary',
r'\bbtn-secondary\b': 'button--secondary',
r'\bbtn-success\b': 'button--success',
r'\bbtn-danger\b': 'button--danger',
r'\bbtn-warning\b': 'button--warning',
r'\bbtn-info\b': 'button--info',
r'\bbtn-light\b': 'button--light',
r'\bbtn-dark\b': 'button--dark',
# Outline варианты
r'\bbtn-outline-primary\b': 'button--outline button--primary',
r'\bbtn-outline-secondary\b': 'button--outline button--secondary',
r'\bbtn-outline-success\b': 'button--outline button--success',
r'\bbtn-outline-danger\b': 'button--outline button--danger',
r'\bbtn-outline-warning\b': 'button--outline button--warning',
r'\bbtn-outline-info\b': 'button--outline button--info',
# Размеры
r'\bbtn-sm\b': 'button--sm',
r'\bbtn-lg\b': 'button--lg',
r'\bbtn-block\b': 'button--block',
# Специальные (кастомные классы, которые уже есть)
r'\bbtn-ghost\b': 'button--ghost',
r'\bbtn-icon\b': 'button--icon',
r'\bbtn-link\b': 'button--link',
# btn-close оставляем как есть (Bootstrap modal close)
}
def migrate_file(filepath):
"""Мигрировать один файл"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
original = content
# Применяем замены
for pattern, replacement in REPLACEMENTS.items():
content = re.sub(pattern, replacement, content)
# Если изменения есть
if content != original:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
except Exception as e:
print(f"Error processing {filepath}: {e}")
return False
def main():
templates_dir = Path('templates')
# Найти все HTML файлы
html_files = list(templates_dir.rglob('*.html'))
print(f"Найдено {len(html_files)} HTML файлов")
print("Начинаем миграцию...\n")
changed_files = []
for filepath in html_files:
if migrate_file(filepath):
changed_files.append(filepath)
print(f"✓ {filepath}")
print(f"\n{'='*60}")
print(f"Миграция завершена!")
print(f"Обработано файлов: {len(html_files)}")
print(f"Изменено файлов: {len(changed_files)}")
print(f"{'='*60}")
if changed_files:
print("\nИзмененные файлы:")
for f in changed_files[:20]: # Показать первые 20
print(f" - {f}")
if len(changed_files) > 20:
print(f" ... и еще {len(changed_files) - 20} файлов")
if __name__ == '__main__':
main()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,293 @@
# SCSS Reorganization - Testing Checklist ✅
**Дата:** 15 января 2026
**Сервер:** http://localhost:9000
**Статус:** 🧪 Готово к тестированию
---
## 📊 CSS Metrics
### Финальные размеры:
- ✅ **app.css:** 137 KB (было 95 KB, +42 KB)
- ✅ **bootstrap-custom.css:** 229 KB (было 301 KB, **-72 KB**)
- ✅ **Итого:** 366 KB (было 396 KB, -30 KB)
### Компиляция:
- ✅ `npm run build:app` - успешно
- ✅ `npm run build:bootstrap` - успешно
- ✅ Нет критических ошибок
---
## 🧪 Checklist визуального тестирования
### Базовая проверка
- [ ] Открыть http://localhost:9000
- [ ] Проверить консоль браузера (F12) - **не должно быть 404 на CSS**
- [ ] Проверить Network tab - загрузились ли app.css и bootstrap-custom.css
### Страницы для тестирования
#### 1. Главная / Feed
- [ ] Открыть `/feed/` или главную
- [ ] **Проверить:**
- [ ] Feed layout выглядит нормально
- [ ] Post form стили применены
- [ ] Members scroller работает
- [ ] Карточки постов отображаются правильно
#### 2. Заявки (Requests)
- [ ] Открыть список заявок
- [ ] **Проверить:**
- [ ] List view работает
- [ ] Детали заявки открываются
- [ ] Recipient picker стили применены
- [ ] Кнопки и формы работают
#### 3. Документы
- [ ] Открыть список документов
- [ ] **Проверить:**
- [ ] Document list view корректен
- [ ] Карточки документов
- [ ] Нет сломанных стилей
#### 4. Сотрудники
- [ ] Открыть список сотрудников
- [ ] **Проверить:**
- [ ] Department controls работают
- [ ] Team visualization (team-viz) отображается
- [ ] Фильтры функционируют
#### 5. Уведомления
- [ ] Открыть notifications
- [ ] **Проверить:**
- [ ] Notification center открывается
- [ ] Badges отображаются
- [ ] Список уведомлений корректен
#### 6. Чат (КРИТИЧНО!)
- [ ] Открыть чат
- [ ] **Проверить:**
- [ ] Chat layout корректен
- [ ] Message inputs работают
- [ ] Chat detail стили применены
- [ ] Date groups отображаются
- [ ] Message selection работает
- [ ] Context menu открывается
- [ ] Reactions отображаются
- [ ] Polls корректны
- [ ] New messages indicator работает
- [ ] Enhanced chat features активны
#### 7. UI Компоненты (Core)
##### Buttons
- [ ] Найти страницу с кнопками
- [ ] **Проверить:**
- [ ] Primary, secondary, success, danger кнопки
- [ ] Размеры: sm, md, lg
- [ ] Hover эффекты
- [ ] Disabled состояние
##### Badges
- [ ] **Проверить:**
- [ ] Badge отображаются (в уведомлениях, чате)
- [ ] Telegram-style badges работают (обратная совместимость)
- [ ] Размеры: sm, lg, xl
- [ ] Цвета: primary, success, danger, warning
##### Cards
- [ ] **Проверить:**
- [ ] Card компонент везде корректен
- [ ] Card header/body/footer
- [ ] Нет сломанных border-radius
##### Modals
- [ ] Открыть любое модальное окно
- [ ] **Проверить:**
- [ ] Modal открывается
- [ ] Backdrop работает
- [ ] Кнопки закрытия
- [ ] Logout modal работает
##### Search
- [ ] Найти search поле
- [ ] **Проверить:**
- [ ] Search input стили (было ios-search)
- [ ] Placeholder
- [ ] Focus состояние
##### Lists
- [ ] **Проверить:**
- [ ] List view работает везде
- [ ] Card list корректен
- [ ] Spacing правильный
#### 8. Layout компоненты
##### Grid
- [ ] **Проверить:**
- [ ] App grid layout корректен
- [ ] Responsive работает
- [ ] Нет сломанных колонок
##### Navbar
- [ ] **Проверить:**
- [ ] Navbar отображается
- [ ] Меню работает
- [ ] Logo/branding на месте
##### Sidebar
- [ ] **Проверить:**
- [ ] Sidebar открывается/закрывается
- [ ] Навигация работает
- [ ] Active состояния
##### Page Header
- [ ] **Проверить:**
- [ ] Page header на каждой странице
- [ ] Breadcrumbs
- [ ] Заголовки
##### Rightbar
- [ ] **Проверить:**
- [ ] Rightbar отображается
- [ ] Calendar widget работает (было rightbar-calendar)
- [ ] Закрытие/открытие
#### 9. Utilities
##### Spacing
- [ ] **Проверить:**
- [ ] Margin классы работают (m-*, mt-*, mb-*, etc.)
- [ ] Padding классы работают (p-*, pt-*, pb-*, etc.)
- [ ] Spacing единообразный (8px grid)
#### 10. Responsive тестирование
- [ ] **Resize браузер:**
- [ ] Desktop (>1200px) - все работает
- [ ] Tablet (768-1200px) - адаптивность
- [ ] Mobile (<768px) - мобильная версия
- [ ] Sidebar collapse на мобильных
- [ ] Chat layout адаптируется
---
## 🐛 Возможные проблемы
### Если что-то сломано:
1. **404 на CSS файлы**
```bash
# Перекомпилировать
cd backend/static
npm run build
```
2. **Стили не применяются**
- Проверить что CSS загружаются (Network tab)
- Hard refresh: Ctrl+Shift+R
- Очистить кеш браузера
3. **Specific компонент сломан**
- Найти файл в новой структуре (см. MIGRATION_MATRIX.md)
- Проверить импорт в main.scss
- Перекомпилировать
4. **Bootstrap классы не работают**
- Проверить что bootstrap-custom.css загружается
- Проверить размер файла (должен быть ~229 KB)
---
## 📋 Консоль браузера - что проверять
### Должно быть:
- ✅ Нет 404 на `.css` файлы
- ✅ Нет ошибок SASS/SCSS
- ✅ Нет warnings о missing файлах
### Red flags:
- ❌ `Failed to load resource: net::ERR_FILE_NOT_FOUND` для CSS
- ❌ `Uncaught SyntaxError` в CSS
- ❌ Warnings о deprecated CSS
---
## 📊 Performance проверка
### В DevTools > Network:
1. Фильтр: CSS
2. **Проверить:**
- [ ] app.css загружается (~137 KB)
- [ ] bootstrap-custom.css загружается (~229 KB)
- [ ] Время загрузки приемлемое (<1s)
- [ ] Нет дублирующихся запросов
### В DevTools > Coverage (опционально):
1. Открыть Coverage tab (Cmd/Ctrl+Shift+P → "Coverage")
2. Reload страницы
3. **Проверить:**
- [ ] app.css usage > 50%
- [ ] bootstrap-custom.css usage > 30%
- [ ] Нет огромного unused CSS
---
## ✅ Критерии успеха
Реорганизация успешна если:
1. ✅ **Все страницы работают** - нет визуальных багов
2. ✅ **Нет 404** на CSS файлы
3. ✅ **Консоль чиста** - нет критических ошибок
4. ✅ **Responsive работает** - на всех экранах
5. ✅ **Bootstrap классы работают** - кнопки, формы, модалы
6. ✅ **Размер CSS приемлемый** - 366 KB total
7. ✅ **Чат полностью функционален** - критично!
8. ✅ **Все компоненты на месте** - ничего не потерялось
---
## 🚀 Если все ОК:
1. ✅ Отметить все пункты в чеклисте
2. ✅ Закрыть issue/task
3. ✅ Обновить документацию если нужно
4. 🎉 **Реорганизация завершена!**
---
## 🔄 Rollback (если нужно)
Если что-то пошло не так:
```bash
cd /c/Users/nadeini/Dev/EUSRR
# Вернуться к предыдущему коммиту
git reset --hard e13ddb9 # Backup commit
# Или восстановить из backup
cd backend/static
rm -rf scss
cp -r scss_backup_20260115 scss
# Перекомпилировать
npm run build
```
---
**Начинай тестирование! 🧪**
**Команды:**
```bash
# Если нужен другой порт
cd backend
.venv/Scripts/python manage.py runserver 0.0.0.0:8000
# Открыть браузер
start http://localhost:9000
```

View File

@ -0,0 +1,530 @@
// =============================================================================
// Custom Button System
// =============================================================================
// Современная система кнопок БЕЗ Bootstrap
// Использует CSS Grid, Custom Properties, современные анимации
//
// ЦЕЛЬ: Заменить Bootstrap buttons полностью
// =============================================================================
// 1. CSS ПЕРЕМЕННЫЕ (ТОКЕНЫ)
// =============================================================================
:root {
// Основные цвета кнопок
--button-primary: var(--bs-primary, #0d6efd);
--button-secondary: var(--bs-secondary, #6c757d);
--button-success: var(--bs-success, #198754);
--button-danger: var(--bs-danger, #dc3545);
--button-warning: var(--bs-warning, #ffc107);
--button-info: var(--bs-info, #0dcaf0);
--button-light: var(--bs-light, #f8f9fa);
--button-dark: var(--bs-dark, #212529);
// Размеры
--button-padding-y: 0.5rem;
--button-padding-x: 1rem;
--button-font-size: 1rem;
--button-border-radius: 0.375rem;
--button-min-width: 80px;
// Эффекты
--button-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
--button-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
--button-shadow-hover: 0 4px 8px rgba(0, 0, 0, 0.15);
--button-shadow-active: 0 1px 2px rgba(0, 0, 0, 0.1);
}
// =============================================================================
// 2. BASE BUTTON
// =============================================================================
.button {
// Layout
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
// Размеры
padding: var(--button-padding-y) var(--button-padding-x);
min-width: var(--button-min-width);
// Текст
font-family: inherit;
font-size: var(--button-font-size);
font-weight: 500;
line-height: 1.5;
text-align: center;
text-decoration: none;
white-space: nowrap;
user-select: none;
// Внешний вид
border: 1px solid transparent;
border-radius: var(--button-border-radius);
background: var(--button-primary);
color: white;
box-shadow: var(--button-shadow);
cursor: pointer;
// Переходы
transition: var(--button-transition);
// Hover
&:hover {
transform: translateY(-1px);
box-shadow: var(--button-shadow-hover);
filter: brightness(1.1);
}
// Active
&:active {
transform: translateY(0);
box-shadow: var(--button-shadow-active);
filter: brightness(0.95);
}
// Focus
&:focus,
&:focus-visible {
outline: 2px solid var(--button-primary);
outline-offset: 2px;
}
// Disabled
&:disabled,
&.disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
transform: none;
box-shadow: none;
}
// Иконки
i, svg {
font-size: 1.2em;
flex-shrink: 0;
}
}
// =============================================================================
// 3. ЦВЕТОВЫЕ ВАРИАНТЫ
// =============================================================================
.button--primary {
background: var(--button-primary);
border-color: var(--button-primary);
color: white;
&:focus-visible {
outline-color: var(--button-primary);
}
}
.button--secondary {
background: var(--button-secondary);
border-color: var(--button-secondary);
color: white;
&:focus-visible {
outline-color: var(--button-secondary);
}
}
.button--success {
background: var(--button-success);
border-color: var(--button-success);
color: white;
&:focus-visible {
outline-color: var(--button-success);
}
}
.button--danger {
background: var(--button-danger);
border-color: var(--button-danger);
color: white;
&:focus-visible {
outline-color: var(--button-danger);
}
}
.button--warning {
background: var(--button-warning);
border-color: var(--button-warning);
color: #212529;
&:focus-visible {
outline-color: var(--button-warning);
}
}
.button--info {
background: var(--button-info);
border-color: var(--button-info);
color: #212529;
&:focus-visible {
outline-color: var(--button-info);
}
}
.button--light {
background: var(--button-light);
border-color: var(--button-light);
color: #212529;
&:focus-visible {
outline-color: var(--button-light);
}
}
.button--dark {
background: var(--button-dark);
border-color: var(--button-dark);
color: white;
&:focus-visible {
outline-color: var(--button-dark);
}
}
// =============================================================================
// 4. OUTLINE ВАРИАНТЫ
// =============================================================================
.button--outline {
background: transparent;
box-shadow: none;
&:hover {
background: var(--button-primary);
color: white;
}
&.button--primary {
border-color: var(--button-primary);
color: var(--button-primary);
}
&.button--secondary {
border-color: var(--button-secondary);
color: var(--button-secondary);
&:hover {
background: var(--button-secondary);
}
}
&.button--success {
border-color: var(--button-success);
color: var(--button-success);
&:hover {
background: var(--button-success);
}
}
&.button--danger {
border-color: var(--button-danger);
color: var(--button-danger);
&:hover {
background: var(--button-danger);
}
}
&.button--warning {
border-color: var(--button-warning);
color: var(--button-warning);
&:hover {
background: var(--button-warning);
color: #212529;
}
}
&.button--info {
border-color: var(--button-info);
color: var(--button-info);
&:hover {
background: var(--button-info);
color: #212529;
}
}
}
// =============================================================================
// 5. GHOST ВАРИАНТ (без рамки)
// =============================================================================
.button--ghost {
background: transparent;
border-color: transparent;
box-shadow: none;
&:hover {
background: rgba(0, 0, 0, 0.05);
}
&.button--primary {
color: var(--button-primary);
}
&.button--secondary {
color: var(--button-secondary);
}
&.button--success {
color: var(--button-success);
}
&.button--danger {
color: var(--button-danger);
}
}
// =============================================================================
// 6. РАЗМЕРЫ
// =============================================================================
.button--sm {
--button-padding-y: 0.25rem;
--button-padding-x: 0.5rem;
--button-font-size: 0.875rem;
--button-min-width: 60px;
}
.button--lg {
--button-padding-y: 0.75rem;
--button-padding-x: 1.5rem;
--button-font-size: 1.125rem;
--button-min-width: 100px;
}
.button--xl {
--button-padding-y: 1rem;
--button-padding-x: 2rem;
--button-font-size: 1.25rem;
--button-min-width: 120px;
}
// =============================================================================
// 7. СПЕЦИАЛЬНЫЕ ВАРИАНТЫ
// =============================================================================
// Кнопка на всю ширину
.button--block {
display: flex;
width: 100%;
min-width: auto;
}
// Квадратная кнопка (только иконка)
.button--icon {
min-width: auto;
padding: var(--button-padding-y);
aspect-ratio: 1;
}
// Круглая кнопка
.button--circle {
min-width: auto;
padding: var(--button-padding-y);
aspect-ratio: 1;
border-radius: 50%;
}
// Без padding (для текста)
.button--link {
padding: 0;
min-width: auto;
background: transparent;
border: none;
box-shadow: none;
text-decoration: underline;
&:hover {
transform: none;
text-decoration: none;
}
&.button--primary {
color: var(--button-primary);
}
&.button--danger {
color: var(--button-danger);
}
}
// =============================================================================
// 8. СОСТОЯНИЯ ЗАГРУЗКИ
// =============================================================================
.button--loading {
position: relative;
color: transparent;
pointer-events: none;
&::after {
content: '';
position: absolute;
width: 1em;
height: 1em;
top: 50%;
left: 50%;
margin-left: -0.5em;
margin-top: -0.5em;
border: 2px solid currentColor;
border-radius: 50%;
border-right-color: transparent;
animation: button-spin 0.6s linear infinite;
}
}
@keyframes button-spin {
to {
transform: rotate(360deg);
}
}
// =============================================================================
// 9. ГРУППЫ КНОПОК
// =============================================================================
.button-group {
display: inline-flex;
gap: 0;
.button {
border-radius: 0;
&:first-child {
border-top-left-radius: var(--button-border-radius);
border-bottom-left-radius: var(--button-border-radius);
}
&:last-child {
border-top-right-radius: var(--button-border-radius);
border-bottom-right-radius: var(--button-border-radius);
}
&:not(:last-child) {
border-right-width: 0;
}
}
}
// Вертикальная группа
.button-group--vertical {
flex-direction: column;
.button {
width: 100%;
&:first-child {
border-radius: 0;
border-top-left-radius: var(--button-border-radius);
border-top-right-radius: var(--button-border-radius);
}
&:last-child {
border-radius: 0;
border-bottom-left-radius: var(--button-border-radius);
border-bottom-right-radius: var(--button-border-radius);
}
&:not(:last-child) {
border-right-width: 1px;
border-bottom-width: 0;
}
}
}
// =============================================================================
// 10. ОБРАТНАЯ СОВМЕСТИМОСТЬ С BOOTSTRAP
// =============================================================================
// Временная поддержка старых классов через @extend
.btn {
@extend .button;
}
.btn-primary {
@extend .button--primary;
}
.btn-secondary {
@extend .button--secondary;
}
.btn-success {
@extend .button--success;
}
.btn-danger {
@extend .button--danger;
}
.btn-warning {
@extend .button--warning;
}
.btn-info {
@extend .button--info;
}
.btn-light {
@extend .button--light;
}
.btn-dark {
@extend .button--dark;
}
.btn-outline-primary {
@extend .button--outline;
@extend .button--primary;
}
.btn-outline-secondary {
@extend .button--outline;
@extend .button--secondary;
}
.btn-outline-success {
@extend .button--outline;
@extend .button--success;
}
.btn-outline-danger {
@extend .button--outline;
@extend .button--danger;
}
.btn-sm {
@extend .button--sm;
}
.btn-lg {
@extend .button--lg;
}
.btn-block {
@extend .button--block;
}
// =============================================================================
// ПРИМЕЧАНИЯ
// =============================================================================
// - Полная замена Bootstrap buttons
// - Современные CSS возможности: Grid, Custom Properties, Animations
// - Обратная совместимость через @extend (временно)
// - После миграции templates удалить секцию 10
// - Можно кастомизировать через CSS переменные без SCSS

View File

@ -16,6 +16,7 @@
// =============================================================================
@import 'core/common';
@import 'core/buttons';
@import 'core/buttons-custom'; // ⭐ Новая система кнопок (замена Bootstrap)
@import 'core/badges';
@import 'core/cards';
@import 'core/lists';

View File

@ -69,13 +69,13 @@
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary btn-lg">
<button type="submit" class="button button--primary button--lg">
<i class="bi bi-box-arrow-in-right me-2"></i>Войти
</button>
<a href="{% url 'auth_front:password_reset' %}" class="btn btn-link mt-2">Забыли пароль?</a>
<a href="{% url 'auth_front:password_reset' %}" class="button button--link mt-2">Забыли пароль?</a>
</div>
<div class="d-grid gap-2 mt-3">
<a class="btn btn-outline-primary btn-lg" href="/auth/register/">
<a class="button button--outline button--primary button--lg" href="/auth/register/">
<i class="bi bi-person-plus me-2"></i>Регистрация
</a>
</div>

View File

@ -34,11 +34,11 @@
<input type="hidden" name="next" value="{{ next|default:'' }}">
<button type="submit" class="btn ios-btn ios-btn-danger" id="confirmBtn">
<button type="submit" class="button ios-button ios-button--danger" id="confirmBtn">
Выйти
</button>
<a href="javascript:void(0)" class="btn ios-btn ios-btn-ghost text-decoration-none text-center" id="cancelBtn">
<a href="javascript:void(0)" class="button ios-button ios-button--ghost text-decoration-none text-center" id="cancelBtn">
Отмена
</a>
</form>

View File

@ -31,7 +31,7 @@
<label for="{{ form.new_password2.id_for_label }}">Подтвердите новый пароль</label>
</div>
</div>
<button type="submit" class="btn btn-primary btn-lg w-100">
<button type="submit" class="button button--primary button--lg w-100">
<i class="bi bi-key me-2"></i>Изменить пароль
</button>
</form>

View File

@ -53,7 +53,7 @@
{% endif %}
</div>
<button type="submit" class="btn btn-primary btn-lg w-100">
<button type="submit" class="button button--primary button--lg w-100">
<i class="bi bi-envelope-arrow-up me-2"></i>Отправить инструкции
</button>
</form>

View File

@ -18,7 +18,7 @@
<div class="card-body text-center">
<i class="bi bi-shield-check-fill display-4 mb-4 text-primary"></i>
<p class="lead">Ваш новый пароль установлен. Теперь вы можете войти в систему.</p>
<a href="{% url 'auth_front:login' %}" class="btn btn-primary btn-lg">
<a href="{% url 'auth_front:login' %}" class="button button--primary button--lg">
<i class="bi bi-box-arrow-in-right me-2"></i>Войти в систему
</a>
</div>

View File

@ -76,7 +76,7 @@
{% endif %}
</div>
<button type="submit" class="btn btn-primary btn-lg w-100">
<button type="submit" class="button button--primary button--lg w-100">
<i class="bi bi-key me-2"></i>Установить пароль
</button>
</form>

View File

@ -21,7 +21,7 @@
На ваш email отправлены инструкции по сбросу пароля.
Проверьте почту и следуйте указаниям в письме.
</p>
<a href="{% url 'auth_front:login' %}" class="btn btn-primary btn-lg">
<a href="{% url 'auth_front:login' %}" class="button button--primary button--lg">
<i class="bi bi-arrow-left me-2"></i>Вернуться к авторизации
</a>
</div>

View File

@ -127,10 +127,10 @@
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary btn-lg">
<button type="submit" class="button button--primary button--lg">
<i class="bi bi-person-plus me-2"></i>Зарегистрироваться
</button>
<a href="{% url 'auth_front:login' %}" class="btn btn-link">Уже есть аккаунт? Войти</a>
<a href="{% url 'auth_front:login' %}" class="button button--link">Уже есть аккаунт? Войти</a>
</div>
</form>
</div>

View File

@ -78,7 +78,7 @@
{% endif %}
</div>
<button type="submit" class="btn btn-primary w-100">Подтвердить</button>
<button type="submit" class="button button--primary w-100">Подтвердить</button>
</form>
{# Повторная отправка — строго POST #}
@ -86,7 +86,7 @@
<form method="post" action="{% url 'auth_front:resend_email' %}">
{% csrf_token %}
<input type="hidden" name="email" value="{{ form.email.value }}">
<button type="submit" class="btn btn-link p-0">Отправить код заново</button>
<button type="submit" class="button button--link p-0">Отправить код заново</button>
</form>
{% endif %}
</div>

View File

@ -13,10 +13,10 @@
</select>
</div>
<div class="col-12 col-sm-4 d-flex justify-content-end gap-2">
<button class="btn btn-outline-primary d-flex align-items-center justify-content-center gap-1" type="button" id="applyChatFilter">
<button class="button button--outline button--primary d-flex align-items-center justify-content-center gap-1" type="button" id="applyChatFilter">
<i class="bi-funnel"></i><span>Применить</span>
</button>
<button type="button" class="btn btn-outline-secondary d-flex align-items-center justify-content-center" id="resetChatFilter" title="Сбросить фильтры">
<button type="button" class="button button--outline button--secondary d-flex align-items-center justify-content-center" id="resetChatFilter" title="Сбросить фильтры">
<i class="bi-x-lg"></i>
</button>
</div>

View File

@ -64,16 +64,16 @@
<div class="chat-header-actions">
{% if chat.type == 'announcement' and user.is_staff %}
{% if chat.is_blocked %}
<button type="button" class="btn btn-success btn-sm" onclick="unblockAnnouncement({{ chat.id }})">
<button type="button" class="button button--success button--sm" onclick="unblockAnnouncement({{ chat.id }})">
<i class="bi-unlock"></i>
</button>
{% else %}
<button type="button" class="btn btn-danger btn-sm" onclick="blockAnnouncement({{ chat.id }})">
<button type="button" class="button button--danger button--sm" onclick="blockAnnouncement({{ chat.id }})">
<i class="bi-lock"></i>
</button>
{% endif %}
{% endif %}
<a href="{% url 'communications:chat_list' %}" class="btn btn-ghost">
<a href="{% url 'communications:chat_list' %}" class="button button--ghost">
<i class="bi-arrow-left"></i>
</a>
</div>
@ -184,7 +184,7 @@
<div class="message-field">
<!-- Кнопка вложений с выпадающим меню -->
<div class="dropdown message-attach">
<button type="button" class="btn btn-ghost btn-attachment message-icon-btn"
<button type="button" class="button button--ghost btn-attachment message-icon-button"
id="attachmentDropdown"
data-bs-toggle="dropdown"
aria-expanded="false"
@ -228,7 +228,7 @@
<!-- Кнопка выбора эмодзи -->
<div class="dropdown message-emoji">
<button type="button" class="btn btn-ghost btn-emoji message-icon-btn"
<button type="button" class="button button--ghost btn-emoji message-icon-button"
id="emojiDropdown"
data-bs-toggle="dropdown"
data-emoji-toggle="1"
@ -249,7 +249,7 @@
placeholder="Напишите сообщение…"></textarea>
<!-- Кнопка отправки -->
<button type="submit" class="btn btn-primary btn-send message-send" title="Отправить">
<button type="submit" class="button button--primary btn-send message-send" title="Отправить">
<i class="bi-send-fill"></i>
</button>
</div>
@ -314,7 +314,7 @@
placeholder="Вариант ответа" maxlength="200">
</div>
</div>
<button type="button" class="btn btn-sm btn-outline-primary" id="addPollOption">
<button type="button" class="button button--sm button--outline button--primary" id="addPollOption">
<i class="bi-plus-circle me-1"></i>Добавить вариант
</button>
</div>
@ -356,10 +356,10 @@
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
<button type="button" class="button button--secondary" data-bs-dismiss="modal">
Отмена
</button>
<button type="button" class="btn btn-primary" id="submitPoll">
<button type="button" class="button button--primary" id="submitPoll">
Создать
</button>
</div>

View File

@ -23,37 +23,37 @@
<div class="chat-type-sidebar">
<div class="card">
<div class="list-group list-group-flush">
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-btn active"
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-button active"
data-chat-type="all" title="Все чаты">
<i class="bi-chat-dots fs-4 d-block"></i>
<span class="badge badge--muted" data-count="all" style="display: none;">0</span>
</button>
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-btn"
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-button"
data-chat-type="global" title="Глобальный">
<i class="bi-globe fs-4 d-block"></i>
<span class="badge badge--muted" data-count="global" style="display: none;">0</span>
</button>
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-btn"
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-button"
data-chat-type="department" title="Отделы">
<i class="bi-diagram-3 fs-4 d-block"></i>
<span class="badge badge--muted" data-count="department" style="display: none;">0</span>
</button>
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-btn"
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-button"
data-chat-type="private" title="Личные">
<i class="bi-person-fill fs-4 d-block"></i>
<span class="badge badge--muted" data-count="private" style="display: none;">0</span>
</button>
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-btn"
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-button"
data-chat-type="group" title="Группы">
<i class="bi-people-fill fs-4 d-block"></i>
<span class="badge badge--muted" data-count="group" style="display: none;">0</span>
</button>
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-btn"
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-button"
data-chat-type="channel" title="Каналы">
<i class="bi-broadcast fs-4 d-block"></i>
<span class="badge badge--muted" data-count="channel" style="display: none;">0</span>
</button>
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-btn"
<button type="button" class="list-group-item list-group-item-action text-center py-3 chat-type-button"
data-chat-type="announcement" title="Объявления">
<i class="bi-megaphone fs-4 d-block"></i>
<span class="badge badge--muted" data-count="announcement" style="display: none;">0</span>
@ -302,8 +302,8 @@
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" id="createChatBtn"><i class="bi-check-lg"></i> Создать</button>
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Отмена</button>
<button class="button button--primary" type="button" id="createChatBtn"><i class="bi-check-lg"></i> Создать</button>
<button type="button" class="button button--outline button--secondary" data-bs-dismiss="modal">Отмена</button>
</div>
</div>
</div>
@ -568,7 +568,7 @@
// ===== ФИЛЬТРАЦИЯ ПО ТИПАМ ЧАТОВ =====
let activeFilter = 'all';
const chatTypeButtons = document.querySelectorAll('.chat-type-btn');
const chatTypeButtons = document.querySelectorAll('.chat-type-button');
const chatSections = document.querySelectorAll('.chat-section');
// Функция подсчета чатов по типам и управления видимостью
@ -642,11 +642,11 @@
activeFilter = filterType;
// Обновляем активную кнопку
chatTypeButtons.forEach(btn => {
if (btn.dataset.chatType === filterType) {
btn.classList.add('active');
chatTypeButtons.forEach(button => {
if (button.dataset.chatType === filterType) {
button.classList.add('active');
} else {
btn.classList.remove('active');
button.classList.remove('active');
}
});
@ -660,9 +660,9 @@
}
// Обработка кликов по кнопкам типов
chatTypeButtons.forEach(btn => {
btn.addEventListener('click', () => {
const filterType = btn.dataset.chatType;
chatTypeButtons.forEach(button => {
button.addEventListener('click', () => {
const filterType = button.dataset.chatType;
applyTypeFilter(filterType);
});
});

View File

@ -12,10 +12,10 @@
</div>
<div class="col-12 col-sm-6 d-flex justify-content-end gap-2">
<button class="btn btn-outline-primary d-flex align-items-center justify-content-center gap-1" type="submit">
<button class="button button--outline button--primary d-flex align-items-center justify-content-center gap-1" type="submit">
<i class="bi-funnel"></i><span>Применить</span>
</button>
<a class="btn btn-outline-secondary d-flex align-items-center justify-content-center" href="?scope={{ scope }}" title="Сбросить фильтры">
<a class="button button--outline button--secondary d-flex align-items-center justify-content-center" href="?scope={{ scope }}" title="Сбросить фильтры">
<i class="bi-x-lg"></i>
</a>
</div>

View File

@ -104,8 +104,8 @@
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="submit"><i class="bi-check-lg"></i> Сохранить</button>
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Отмена</button>
<button class="button button--primary" type="submit"><i class="bi-check-lg"></i> Сохранить</button>
<button type="button" class="button button--outline button--secondary" data-bs-dismiss="modal">Отмена</button>
</div>
</form>
</div>
@ -162,8 +162,8 @@
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="submit"><i class="bi-check-lg"></i> Сохранить</button>
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Отмена</button>
<button class="button button--primary" type="submit"><i class="bi-check-lg"></i> Сохранить</button>
<button type="button" class="button button--outline button--secondary" data-bs-dismiss="modal">Отмена</button>
</div>
</form>
</div>
@ -203,7 +203,7 @@
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Закрыть</button>
<button type="button" class="button button--outline button--secondary" data-bs-dismiss="modal">Закрыть</button>
</div>
</div>
</div>

View File

@ -28,7 +28,7 @@
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary btn-sm">
<button type="submit" class="button button--primary button--sm">
<i class="bi-check2 me-1"></i>Сохранить
</button>
</div>
@ -71,7 +71,7 @@
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary btn-sm">
<button type="submit" class="button button--primary button--sm">
<i class="bi-check2 me-1"></i>Сохранить
</button>
</div>
@ -122,7 +122,7 @@
<div class="col-12">
<button type="button"
class="btn btn-outline-secondary btn-sm me-2"
class="button button--outline button--secondary button--sm me-2"
data-bs-toggle="modal"
data-bs-target="#rolePermsEditModal"
{% if not dept_perm_choices %}disabled{% endif %}>
@ -132,15 +132,15 @@
</div>
<div class="col-12 d-flex flex-wrap gap-2">
<button type="submit" class="btn btn-primary btn-sm" id="roleSaveBtn" disabled>
<button type="submit" class="button button--primary button--sm" id="roleSaveBtn" disabled>
<i class="bi-check2 me-1"></i>Сохранить
</button>
<button type="button" class="btn btn-outline-danger btn-sm" id="roleDeleteBtn" disabled>
<button type="button" class="button button--outline button--danger button--sm" id="roleDeleteBtn" disabled>
<i class="bi-trash me-1"></i>Удалить
</button>
<button type="button"
id="toggleNewRole"
class="btn btn-outline-secondary btn-sm"
class="button button--outline button--secondary button--sm"
data-toggle-target="#roleCreateForm">
<i class="bi-plus-lg me-1"></i>Новая роль
</button>
@ -167,7 +167,7 @@
<div class="col-12">
<button type="button"
class="btn btn-outline-secondary btn-sm me-2"
class="button button--outline button--secondary button--sm me-2"
data-bs-toggle="modal"
data-bs-target="#rolePermsCreateModal"
{% if not dept_perm_choices %}disabled{% endif %}>
@ -177,10 +177,10 @@
</div>
<div class="col-12 d-flex gap-2">
<button type="submit" class="btn btn-success btn-sm">
<button type="submit" class="button button--success button--sm">
<i class="bi-plus-lg me-1"></i>Создать
</button>
<button type="button" id="cancelNewRole" class="btn btn-ghost btn-sm">
<button type="button" id="cancelNewRole" class="button button--ghost button--sm">
<i class="bi-x-lg me-1"></i>Отмена
</button>
</div>
@ -221,7 +221,7 @@
{% endif %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" id="applyPermsEdit" data-bs-dismiss="modal">
<button type="button" class="button button--primary button--sm" id="applyPermsEdit" data-bs-dismiss="modal">
<i class="bi-check2 me-1"></i>Готово
</button>
</div>
@ -252,7 +252,7 @@
{% endif %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" id="applyPermsCreate" data-bs-dismiss="modal">
<button type="button" class="button button--primary button--sm" id="applyPermsCreate" data-bs-dismiss="modal">
<i class="bi-check2 me-1"></i>Готово
</button>
</div>

View File

@ -33,7 +33,7 @@
</div>
<div class="col-12 col-lg-3 d-flex align-items-end gap-2">
<button type="submit" class="btn btn-primary">Применить</button>
<a href="{% url 'employees:employees_list' %}" class="btn btn-outline-secondary">Сбросить</a>
<button type="submit" class="button button--primary">Применить</button>
<a href="{% url 'employees:employees_list' %}" class="button button--outline button--secondary">Сбросить</a>
</div>
</form>

View File

@ -13,8 +13,8 @@
<form method="post">
{% csrf_token %}
<div class="d-flex gap-2">
<button type="submit" class="btn btn-danger">Удалить</button>
<a href="{% url 'employees:absence_list' %}" class="btn btn-outline-secondary">Отмена</a>
<button type="submit" class="button button--danger">Удалить</button>
<a href="{% url 'employees:absence_list' %}" class="button button--outline button--secondary">Отмена</a>
</div>
</form>
</div>

View File

@ -6,6 +6,6 @@
<form method="post" enctype="multipart/form-data" class="card p-4 shadow-sm">
{% csrf_token %}
{% bootstrap_form form layout='horizontal' %}
<button type="submit" class="btn btn-primary">Отправить заявление</button>
<button type="submit" class="button button--primary">Отправить заявление</button>
</form>
{% endblock %}

View File

@ -6,7 +6,7 @@
<div class="container">
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 class="mb-0">Мои отсутствия</h3>
<a href="{% url 'employees:absence_add' %}" class="btn btn-primary">
<a href="{% url 'employees:absence_add' %}" class="button button--primary">
<i class="bi-plus-circle"></i> Новая запись
</a>
</div>
@ -29,8 +29,8 @@
{% endif %}
</div>
<div class="d-flex gap-2">
<a href="{% url 'employees:absence_edit' a.pk %}" class="btn btn-sm btn-outline-secondary">Править</a>
<a href="{% url 'employees:absence_delete' a.pk %}" class="btn btn-sm btn-outline-danger">Удалить</a>
<a href="{% url 'employees:absence_edit' a.pk %}" class="button button--sm button--outline button--secondary">Править</a>
<a href="{% url 'employees:absence_delete' a.pk %}" class="button button--sm button--outline button--danger">Удалить</a>
</div>
</div>
</div>

View File

@ -7,7 +7,7 @@
{# Добавить участника #}
<button type="button"
class="btn-icon btn-icon--success"
class="button--icon button--icon--success"
data-bs-toggle="modal"
data-bs-target="#addMemberModal-{{ dept.id }}"
data-bs-toggle="tooltip"
@ -20,7 +20,7 @@
{% if roles %}
{% if user.is_superuser or user.is_staff or can_assign_roles or dept.head.id == user.id %}
<button type="button"
class="btn-icon btn-icon--primary"
class="button--icon button--icon--primary"
data-bs-toggle="modal"
data-bs-target="#setRoleModal-{{ dept.id }}"
data-bs-toggle="tooltip"
@ -33,7 +33,7 @@
{# Удалить участника #}
<button type="button"
class="btn-icon btn-icon--danger"
class="button--icon button--icon--danger"
data-bs-toggle="modal"
data-bs-target="#removeMemberModal-{{ dept.id }}"
data-bs-toggle="tooltip"
@ -49,7 +49,7 @@
{% url 'feed:post_create' as post_create_url %}
{% if user.is_authenticated and user.id in members_exclude_ids %}
<a href="{{ post_create_url }}?department={{ dept_id }}&next={{ request.get_full_path|urlencode }}"
class="btn btn-primary">
class="button button--primary">
<i class="bi-plus-circle me-1"></i> Создать публикацию
</a>
{% endif %}

View File

@ -47,10 +47,10 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-link" data-bs-dismiss="modal">
<button type="button" class="button button--link" data-bs-dismiss="modal">
<i class="bi-x-lg me-1"></i>Отмена
</button>
<button type="submit" id="removeMemberSubmit-{{ dept.id }}" class="btn btn-outline-danger" disabled>
<button type="submit" id="removeMemberSubmit-{{ dept.id }}" class="button button--outline button--danger" disabled>
<i class="bi-person-dash me-1"></i>Удалить
</button>
</div>
@ -103,10 +103,10 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-link" data-bs-dismiss="modal">
<button type="button" class="button button--link" data-bs-dismiss="modal">
<i class="bi-x-lg me-1"></i>Отмена
</button>
<button type="submit" id="addMemberSubmit-{{ dept.id }}" class="btn btn-success"
<button type="submit" id="addMemberSubmit-{{ dept.id }}" class="button button--success"
data-add-member-submit disabled>
<i class="bi-person-plus me-1"></i>Добавить
</button>
@ -178,10 +178,10 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-link" data-bs-dismiss="modal">
<button type="button" class="button button--link" data-bs-dismiss="modal">
<i class="bi-x-lg me-1"></i>Отмена
</button>
<button type="submit" id="setRoleSubmit-{{ dept.id }}" class="btn btn-primary" disabled>
<button type="submit" id="setRoleSubmit-{{ dept.id }}" class="button button--primary" disabled>
<i class="bi-check2 me-1"></i>Сохранить
</button>
</div>

View File

@ -7,7 +7,7 @@
<i class="bi-gear"></i>
<div class="ios-section-title mb-0">Настройки отдела</div>
<div class="ms-auto">
<button type="button" class="btn btn-sm btn-ghost"
<button type="button" class="button button--sm button--ghost"
data-bs-toggle="collapse" data-bs-target="#deptEditWrap-{{ dept.id }}">
Скрыть
</button>
@ -42,7 +42,7 @@
{% if page|default:0 %}
<div>
{% if page|add:"-1" %}
<a class="btn btn-outline-secondary btn-sm" href="?page={{ page|add:'-1' }}">← Назад</a>
<a class="button button--outline button--secondary button--sm" href="?page={{ page|add:'-1' }}">← Назад</a>
{% endif %}
</div>
{% endif %}

View File

@ -2,9 +2,9 @@
{# Кнопки сохранения и отмены формы #}
<div class="col-12 d-flex gap-2 mt-2">
<button type="submit" class="btn btn-primary">
<button type="submit" class="button button--primary">
<span class="btn-label"><i class="bi-check2 me-1"></i>Сохранить</span>
<span class="btn-spinner d-none spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-ghost" data-bs-toggle="collapse" data-bs-target="#editFormWrap">Отмена</button>
<button type="button" class="button button--ghost" data-bs-toggle="collapse" data-bs-target="#editFormWrap">Отмена</button>
</div>

View File

@ -45,7 +45,7 @@
• Форматы: JPG, PNG, GIF. Максимум 10 МБ
</small>
{% if emp.avatar %}
<button type="button" class="btn btn-sm btn-outline-danger mt-2" id="removeAvatarBtn">
<button type="button" class="button button--sm button--outline button--danger mt-2" id="removeAvatarBtn">
<i class="bi-trash"></i> Удалить фото
</button>
{% endif %}

View File

@ -43,7 +43,7 @@
{% if can_create_position or request.user.is_staff or request.user.is_superuser %}
<div class="col-md-6">
<label class="form-label d-block">Новая должность</label>
<button type="button" class="btn btn-outline-secondary btn-sm"
<button type="button" class="button button--outline button--secondary button--sm"
data-bs-toggle="collapse" data-bs-target="#newPositionPane" aria-expanded="false" aria-controls="newPositionPane">
Создать должность
</button>
@ -92,8 +92,8 @@
</div>
</div>
<div class="modal-footer">
<button type="button" id="groupsClear" class="btn btn-ghost">Сбросить</button>
<button type="button" id="groupsDone" class="btn btn-primary" data-bs-dismiss="modal">Готово</button>
<button type="button" id="groupsClear" class="button button--ghost">Сбросить</button>
<button type="button" id="groupsDone" class="button button--primary" data-bs-dismiss="modal">Готово</button>
</div>
</div>
</div>
@ -108,15 +108,15 @@
{% endif %}
<div class="col-12 d-flex flex-wrap gap-2 mt-1">
<button type="button" class="btn btn-outline-secondary btn-sm"
<button type="button" class="button button--outline button--secondary button--sm"
data-bs-toggle="modal" data-bs-target="#groupsPickerModal">
Выбрать группы полномочий
</button>
<button type="button" class="btn btn-primary btn-sm" id="posCreateBtn">
<button type="button" class="button button--primary button--sm" id="posCreateBtn">
<span class="lbl">Создать и назначить</span>
<span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-ghost btn-sm"
<button type="button" class="button button--ghost button--sm"
data-bs-toggle="collapse" data-bs-target="#newPositionPane">Отмена</button>
</div>
@ -131,7 +131,7 @@
{# РЕДАКТИРОВАТЬ ВЫБРАННУЮ #}
<div class="col-12">
<div class="mt-2">
<button type="button" class="btn btn-outline-secondary btn-sm"
<button type="button" class="button button--outline button--secondary button--sm"
data-bs-toggle="collapse" data-bs-target="#editPositionPane"
id="toggleEditPositionBtn" aria-expanded="false" aria-controls="editPositionPane">
Редактировать должность
@ -155,11 +155,11 @@
<div id="pos_edit_groups_chips" class="chips mb-2"></div>
<input type="hidden" id="pos_edit_groups_hidden" value="">
<div class="d-flex flex-wrap gap-2">
<button type="button" class="btn btn-outline-secondary btn-sm"
<button type="button" class="button button--outline button--secondary button--sm"
data-bs-toggle="modal" data-bs-target="#posEditGroupsPickerModal">
Выбрать группы
</button>
<button type="button" class="btn btn-ghost btn-sm" id="posEditClearGroups">Очистить</button>
<button type="button" class="button button--ghost button--sm" id="posEditClearGroups">Очистить</button>
</div>
</div>
@ -186,8 +186,8 @@
</div>
</div>
<div class="modal-footer">
<button type="button" id="posEditGroupsClear" class="btn btn-ghost">Сбросить</button>
<button type="button" id="posEditGroupsDone" class="btn btn-primary" data-bs-dismiss="modal">Готово</button>
<button type="button" id="posEditGroupsClear" class="button button--ghost">Сбросить</button>
<button type="button" id="posEditGroupsDone" class="button button--primary" data-bs-dismiss="modal">Готово</button>
</div>
</div>
</div>
@ -195,15 +195,15 @@
{% endif %}
<div class="col-12 d-flex flex-wrap gap-2 mt-1">
<button type="button" class="btn btn-outline-secondary btn-sm" id="posEditLoadBtn">
<button type="button" class="button button--outline button--secondary button--sm" id="posEditLoadBtn">
<span class="lbl">Загрузить из выбранной</span>
<span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-primary btn-sm" id="posEditSaveBtn">
<button type="button" class="button button--primary button--sm" id="posEditSaveBtn">
<span class="lbl">Сохранить изменения</span>
<span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-ghost btn-sm"
<button type="button" class="button button--ghost button--sm"
data-bs-toggle="collapse" data-bs-target="#editPositionPane">Отмена</button>
</div>
@ -268,16 +268,16 @@
<div class="col-12">
<div class="d-flex flex-wrap gap-2">
<button type="button"
class="btn btn-outline-secondary btn-sm"
class="button button--outline button--secondary button--sm"
data-bs-toggle="modal"
data-bs-target="#empGroupsPickerModal">
Выбрать группы
</button>
<button type="button" class="btn btn-primary btn-sm" id="empGroupsAssignBtn">
<button type="button" class="button button--primary button--sm" id="empGroupsAssignBtn">
<span class="lbl">Назначить выбранные</span>
<span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-outline-danger btn-sm" id="empGroupsRemoveBtn">
<button type="button" class="button button--outline button--danger button--sm" id="empGroupsRemoveBtn">
<span class="lbl">Снять выбранные</span>
<span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</button>
@ -292,7 +292,7 @@
<label class="form-label">Создать новую группу</label>
<div class="input-group">
<input id="empGroupsCreateName" class="form-control" placeholder="CN (имя группы)">
<button type="button" class="btn btn-outline-secondary" id="empGroupsCreateBtn">
<button type="button" class="button button--outline button--secondary" id="empGroupsCreateBtn">
<span class="lbl">Создать</span>
<span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</button>
@ -311,7 +311,7 @@
{% endif %}
{% endfor %}
</select>
<button type="button" class="btn btn-outline-danger" id="empGroupsDeleteBtn">
<button type="button" class="button button--outline button--danger" id="empGroupsDeleteBtn">
<span class="lbl">Удалить</span>
<span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</button>
@ -346,8 +346,8 @@
</div>
</div>
<div class="modal-footer">
<button type="button" id="empGroupsClear" class="btn btn-ghost">Сбросить</button>
<button type="button" id="empGroupsDone" class="btn btn-primary" data-bs-dismiss="modal">Готово</button>
<button type="button" id="empGroupsClear" class="button button--ghost">Сбросить</button>
<button type="button" id="empGroupsDone" class="button button--primary" data-bs-dismiss="modal">Готово</button>
</div>
</div>
</div>

View File

@ -31,8 +31,8 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
<button type="submit" class="btn btn-primary" id="createDepartmentSubmit">
<button type="button" class="button button--secondary" data-bs-dismiss="modal">Отмена</button>
<button type="submit" class="button button--primary" id="createDepartmentSubmit">
<i class="bi-check-lg me-1"></i>Создать
</button>
</div>

View File

@ -13,8 +13,8 @@
<form method="post">
{% csrf_token %}
<div class="d-flex gap-2">
<button type="submit" class="btn btn-danger">Удалить</button>
<a href="{% url 'employees:department_detail' object.pk %}" class="btn btn-outline-secondary">Отмена</a>
<button type="submit" class="button button--danger">Удалить</button>
<a href="{% url 'employees:department_detail' object.pk %}" class="button button--outline button--secondary">Отмена</a>
</div>
</form>
</div>

View File

@ -10,8 +10,8 @@
{% csrf_token %}
{% bootstrap_form form %}
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Сохранить</button>
<a href="{% url 'employees:department_list' %}" class="btn btn-outline-secondary">Отмена</a>
<button type="submit" class="button button--primary">Сохранить</button>
<a href="{% url 'employees:department_list' %}" class="button button--outline button--secondary">Отмена</a>
</div>
</form>
</div>

View File

@ -62,7 +62,7 @@
{# Пагинация #}
{% if next_url or prev_url %}
<div class="d-flex justify-content-between align-items-center mt-3">
<a class="btn btn-outline-secondary {% if not prev_url %}disabled{% endif %}"
<a class="button button--outline button--secondary {% if not prev_url %}disabled{% endif %}"
href="{{ prev_url|default:'#' }}"
{% if not prev_url %}aria-disabled="true"{% endif %}>
<i class="bi-arrow-left"></i> Назад
@ -70,7 +70,7 @@
{% if count %}
<span class="text-body-secondary small">Всего: {{ count }}</span>
{% endif %}
<a class="btn btn-outline-secondary {% if not next_url %}disabled{% endif %}"
<a class="button button--outline button--secondary {% if not next_url %}disabled{% endif %}"
href="{{ next_url|default:'#' }}"
{% if not next_url %}aria-disabled="true"{% endif %}>
Вперёд <i class="bi-arrow-right"></i>

View File

@ -12,7 +12,7 @@
<i class="bi-person-gear fs-2 text-primary"></i>
<h2 class="title mb-0">Роль в отделе</h2>
<span class="ms-2 small text-secondary text-truncate">— {{ department.name }}</span>
<a href="{{ next_url }}" class="btn btn-ghost ms-auto">
<a href="{{ next_url }}" class="button button--ghost ms-auto">
<i class="bi-arrow-left"></i> Назад
</a>
</div>
@ -52,10 +52,10 @@
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary px-4">
<button type="submit" class="button button--primary px-4">
<i class="bi-check2"></i> Сохранить
</button>
<a href="{{ next_url }}" class="btn btn-ghost">Отмена</a>
<a href="{{ next_url }}" class="button button--ghost">Отмена</a>
</div>
</form>
</div>

View File

@ -43,8 +43,8 @@
</div>
</div>
<div class="card-footer d-flex justify-content-end gap-2">
<a href="{% url 'employees:employees_list' %}" class="btn btn-outline-secondary">Отмена</a>
<button class="btn btn-primary" type="submit">Создать</button>
<a href="{% url 'employees:employees_list' %}" class="button button--outline button--secondary">Отмена</a>
<button class="button button--primary" type="submit">Создать</button>
</div>
</form>
</div>

View File

@ -51,7 +51,7 @@
{{ emp.last_name }} {{ emp.first_name }}{% if emp.patronymic %} {{ emp.patronymic }}{% endif %}
</div>
{% if can_edit %}
<button class="btn-icon"
<button class="button--icon"
type="button"
data-bs-toggle="collapse"
data-bs-target="#editFormWrap"
@ -61,7 +61,7 @@
<i class="bi-pencil-square"></i>
</button>
<noscript>
<a class="btn btn-link p-0" href="{% url 'employees:employee_edit' emp.id %}">Редактировать</a>
<a class="button button--link p-0" href="{% url 'employees:employee_edit' emp.id %}">Редактировать</a>
</noscript>
{% endif %}
</div>
@ -190,8 +190,8 @@
{% endif %}
{% endfor %}
</select>
<button type="submit" class="btn btn-sm btn-primary dept-role-save" disabled>OK</button>
<button type="button" class="btn btn-sm btn-ghost"
<button type="submit" class="button button--sm button--primary dept-role-save" disabled>OK</button>
<button type="button" class="button button--sm button--ghost"
data-bs-toggle="collapse" data-bs-target="#roleEditor-{{ d.id }}">Отмена</button>
</form>
</div>
@ -368,10 +368,10 @@
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<button type="submit" class="button button--primary">
<i class="bi-check-lg me-1"></i>Сохранить событие
</button>
<button type="button" class="btn btn-ghost" data-bs-toggle="collapse" data-bs-target="#actionsManageCollapse">
<button type="button" class="button button--ghost" data-bs-toggle="collapse" data-bs-target="#actionsManageCollapse">
Отмена
</button>
</div>
@ -406,7 +406,7 @@
data-skill-name="{{ sk_name }}">
<span class="lbl">{{ sk_name }}</span>
{% if perms.employees.manage_employee_skills or request.user.is_staff or request.user.is_superuser or is_me %}
<button type="button" class="chip-del-btn" title="Убрать навык" aria-label="Убрать навык">
<button type="button" class="chip-del-button" title="Убрать навык" aria-label="Убрать навык">
<i class="bi bi-dash-lg"></i>
</button>
{% endif %}
@ -443,10 +443,10 @@
</datalist>
</div>
<div class="col-12 d-flex gap-2">
<button type="submit" class="btn btn-primary btn-sm">
<button type="submit" class="button button--primary button--sm">
<i class="bi bi-plus-lg me-1"></i>Добавить
</button>
<button type="button" class="btn btn-ghost btn-sm" data-bs-toggle="collapse" data-bs-target="#skillsForm">
<button type="button" class="button button--ghost button--sm" data-bs-toggle="collapse" data-bs-target="#skillsForm">
Отмена
</button>
</div>
@ -470,7 +470,7 @@
<i class="bi-pencil-square"></i>
<div class="ios-section-title mb-0">Редактирование профиля</div>
<div class="ms-auto">
<button type="button" class="btn btn-sm btn-ghost"
<button type="button" class="button button--sm button--ghost"
data-bs-toggle="collapse" data-bs-target="#editFormWrap">Скрыть</button>
</div>
</div>

View File

@ -34,7 +34,7 @@
{# Пагинация #}
{% if next_url or prev_url %}
<div class="d-flex justify-content-between align-items-center mt-3">
<a class="btn btn-outline-secondary {% if not prev_url %}disabled{% endif %}"
<a class="button button--outline button--secondary {% if not prev_url %}disabled{% endif %}"
href="{{ prev_url|default:'#' }}"
{% if not prev_url %}aria-disabled="true"{% endif %}>
<i class="bi-arrow-left"></i> Назад
@ -42,7 +42,7 @@
{% if count %}
<span class="text-body-secondary small">Всего: {{ count }}</span>
{% endif %}
<a class="btn btn-outline-secondary {% if not next_url %}disabled{% endif %}"
<a class="button button--outline button--secondary {% if not next_url %}disabled{% endif %}"
href="{{ next_url|default:'#' }}"
{% if not next_url %}aria-disabled="true"{% endif %}>
Вперёд <i class="bi-arrow-right"></i>

View File

@ -69,8 +69,8 @@
</div>
<div class="col-12 col-lg-3 d-flex align-items-end gap-2">
<button type="submit" class="btn btn-primary">Применить</button>
<a href="{% url 'employees:employees_list' %}" class="btn btn-outline-secondary">Сбросить</a>
<button type="submit" class="button button--primary">Применить</button>
<a href="{% url 'employees:employees_list' %}" class="button button--outline button--secondary">Сбросить</a>
</div>
</form>
</div>

View File

@ -10,7 +10,7 @@
<!-- Шапка страницы -->
<div class="d-flex align-items-center justify-content-between mb-3">
<div class="d-flex align-items-center gap-2">
<a href="{% url 'employees:department_detail' department.pk %}" class="btn btn-outline-primary btn-sm">
<a href="{% url 'employees:department_detail' department.pk %}" class="button button--outline button--primary button--sm">
<i class="bi-arrow-left"></i>
</a>
<h2 class="mb-0 fw-bold">Пригласить в отдел</h2>
@ -42,10 +42,10 @@
<div class="alert alert-light border rounded-3">
Кажется, всех уже пригласили — в этом отделе больше некому отправить приглашение.
<div class="mt-2">
<a class="btn btn-sm btn-outline-primary" href="{% url 'employees:department_detail' department.pk %}">
<a class="button button--sm button--outline button--primary" href="{% url 'employees:department_detail' department.pk %}">
Вернуться к отделу
</a>
<a class="btn btn-sm btn-outline-secondary ms-2" href="{% url 'employees:employees_list' %}">
<a class="button button--sm button--outline button--secondary ms-2" href="{% url 'employees:employees_list' %}">
Список всех сотрудников
</a>
</div>
@ -71,10 +71,10 @@
</div>
<div class="mt-4 d-flex gap-2">
<button type="submit" class="btn btn-success" id="inviteBtn" disabled>
<button type="submit" class="button button--success" id="inviteBtn" disabled>
<i class="bi-person-plus"></i> Пригласить
</button>
<a href="{% url 'employees:department_detail' department.pk %}" class="btn btn-outline-secondary">Отмена</a>
<a href="{% url 'employees:department_detail' department.pk %}" class="button button--outline button--secondary">Отмена</a>
</div>
</div>
</form>
@ -90,12 +90,12 @@ import { norm } from '{% static "js/utils/stringUtils.js" %}';
(function () {
const search = document.getElementById('employeeSearch');
const select = document.querySelector('select[name="{{ form.employee.html_name }}"]');
const btn = document.getElementById('inviteBtn');
const button = document.getElementById('inviteBtn');
if (!select) return;
// Кнопка активна только при выбранном значении
function toggleBtn() { btn && (btn.disabled = !select.value); }
function toggleBtn() { button && (button.disabled = !select.value); }
select.addEventListener('change', toggleBtn);
toggleBtn();

View File

@ -101,8 +101,8 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
<button type="submit" class="btn btn-primary" id="createEmployeeSubmit">
<button type="button" class="button button--secondary" data-bs-dismiss="modal">Отмена</button>
<button type="submit" class="button button--primary" id="createEmployeeSubmit">
<i class="bi-check-lg me-1"></i>Создать
</button>
</div>

View File

@ -10,8 +10,8 @@
<form method="post">
{% csrf_token %}
<div class="d-flex gap-2">
<button type="submit" class="btn btn-danger">Удалить</button>
<a href="{% url 'employees:skill_list' %}" class="btn btn-outline-secondary">Отмена</a>
<button type="submit" class="button button--danger">Удалить</button>
<a href="{% url 'employees:skill_list' %}" class="button button--outline button--secondary">Отмена</a>
</div>
</form>
</div>

View File

@ -10,8 +10,8 @@
{% csrf_token %}
{% bootstrap_form form %}
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Сохранить</button>
<a href="{% url 'employees:skill_list' %}" class="btn btn-outline-secondary">Отмена</a>
<button type="submit" class="button button--primary">Сохранить</button>
<a href="{% url 'employees:skill_list' %}" class="button button--outline button--secondary">Отмена</a>
</div>
</form>
</div>

View File

@ -7,7 +7,7 @@
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 class="mb-0">Навыки</h3>
{% if user.is_authenticated %}
<a href="{% url 'employees:skill_add' %}" class="btn btn-primary">
<a href="{% url 'employees:skill_add' %}" class="button button--primary">
<i class="bi-plus-circle"></i> Добавить
</a>
{% endif %}
@ -34,8 +34,8 @@
<td>{{ s.level|default:"—" }}</td>
<td class="text-muted">{{ s.description|default:"" }}</td>
<td class="text-end">
<a href="{% url 'employees:skill_edit' s.pk %}" class="btn btn-sm btn-outline-secondary">Править</a>
<a href="{% url 'employees:skill_delete' s.pk %}" class="btn btn-sm btn-outline-danger">Удалить</a>
<a href="{% url 'employees:skill_edit' s.pk %}" class="button button--sm button--outline button--secondary">Править</a>
<a href="{% url 'employees:skill_delete' s.pk %}" class="button button--sm button--outline button--danger">Удалить</a>
</td>
</tr>
{% endfor %}

View File

@ -85,7 +85,7 @@
{% if body|wordcount > 42 %}
<div class="feed-text mb-1" id="excerpt-{{ post_id }}">
{{ body|truncatewords:42 }}
<button class="btn p-0 mt-1 small text-secondary text-decoration-none bg-transparent border-0 readmore-toggle"
<button class="button p-0 mt-1 small text-secondary text-decoration-none bg-transparent border-0 readmore-toggle"
id="more-{{ post_id }}"
type="button"
data-bs-toggle="collapse"
@ -95,10 +95,10 @@
<span class="txt-more">Подробнее</span>
</button>
</div>
<div id="full-{{ post_id }}" class="collapse" data-excerpt="#excerpt-{{ post_id }}" data-btn="#more-{{ post_id }}">
<div id="full-{{ post_id }}" class="collapse" data-excerpt="#excerpt-{{ post_id }}" data-button="#more-{{ post_id }}">
<div class="feed-full mt-1">
{{ body|linebreaksbr }}
<button class="btn p-0 mt-1 small text-secondary text-decoration-none bg-transparent readmore-toggle"
<button class="button p-0 mt-1 small text-secondary text-decoration-none bg-transparent readmore-toggle"
type="button"
data-bs-toggle="collapse"
data-bs-target="#full-{{ post_id }}"
@ -116,7 +116,7 @@
<footer class="card-actions border-0">
{% if post_id %}
{% if user.is_authenticated %}
<button class="btn btn-ghost d-inline-flex align-items-center gap-1"
<button class="button button--ghost d-inline-flex align-items-center gap-1"
type="button"
data-bs-toggle="collapse"
data-bs-target="#ccoll-{{ post_id }}"
@ -127,7 +127,7 @@
<span class="txt-close">Скрыть</span>
</button>
{% else %}
<a href="#" data-post-link data-post-id="{{ post_id }}" class="btn btn-ghost d-inline-flex align-items-center gap-1">
<a href="#" data-post-link data-post-id="{{ post_id }}" class="button button--ghost d-inline-flex align-items-center gap-1">
<i class="bi-chat-dots"></i><span>{{ post.comments_count|default:0 }}</span>
</a>
{% endif %}
@ -135,19 +135,19 @@
{% if post.attachment %}
{% firstof post.attachment.url post.attachment as att_url %}
{% if att_url %}
<a href="{{ att_url }}" class="btn btn-ghost d-inline-flex align-items-center gap-1">
<a href="{{ att_url }}" class="button button--ghost d-inline-flex align-items-center gap-1">
<i class="bi-paperclip"></i><span>Вложение</span>
</a>
{% endif %}
{% endif %}
<span class="ms-auto"></span>
{% if user.is_authenticated and post_id %}
<button type="button" class="btn btn-ghost d-inline-flex align-items-center gap-1 like-btn-card" data-post-id="{{ post_id }}" data-liked="{% if post.is_liked %}true{% else %}false{% endif %}">
<button type="button" class="button button--ghost d-inline-flex align-items-center gap-1 like-btn-card" data-post-id="{{ post_id }}" data-liked="{% if post.is_liked %}true{% else %}false{% endif %}">
<i class="bi-heart{% if post.is_liked %}-fill text-danger{% endif %}"></i>
<span class="like-count">{{ post.likes_count|default:0 }}</span>
</button>
{% else %}
<span class="btn btn-ghost d-inline-flex align-items-center gap-1">
<span class="button button--ghost d-inline-flex align-items-center gap-1">
<i class="bi-heart"></i>
<span>{{ post.likes_count|default:0 }}</span>
</span>
@ -211,7 +211,7 @@
<div class="message-field message-field--compact">
<!-- Кнопка выбора эмодзи -->
<div class="dropdown message-emoji">
<button type="button" class="btn btn-ghost btn-emoji message-icon-btn"
<button type="button" class="button button--ghost btn-emoji message-icon-button"
data-bs-toggle="dropdown"
aria-expanded="false"
title="Вставить смайлик">
@ -222,7 +222,7 @@
</div>
</div>
<textarea name="text" class="form-control message-input" rows="1" placeholder="Оставить комментарий…" required></textarea>
<button class="btn btn-primary message-send" type="submit" title="Отправить"><i class="bi-send"></i></button>
<button class="button button--primary message-send" type="submit" title="Отправить"><i class="bi-send"></i></button>
</div>
</form>
{% endif %}

View File

@ -45,8 +45,8 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
<button type="submit" class="btn btn-primary" id="createPostSubmit">
<button type="button" class="button button--secondary" data-bs-dismiss="modal">Отмена</button>
<button type="submit" class="button button--primary" id="createPostSubmit">
<i class="bi-check-lg me-1"></i>Опубликовать
</button>
</div>

View File

@ -10,7 +10,7 @@
</div>
<div class="mb-3">
<a href="{% url 'feed:post_create' %}?department={{ department.pk }}" class="btn btn-primary">
<a href="{% url 'feed:post_create' %}?department={{ department.pk }}" class="button button--primary">
<i class="bi-plus-circle"></i> Новая публикация
</a>
</div>
@ -49,7 +49,7 @@
<span class="badge bg-warning text-dark"></span>
{% endif %}
{% if department.head == user %}
<a href="{% url 'feed:pin_post' post.pk %}" class="btn btn-sm btn-outline-warning ms-2">
<a href="{% url 'feed:pin_post' post.pk %}" class="button button--sm button--outline button--warning ms-2">
{% if post.pinned %} Открепить {% else %} Закрепить {% endif %}
</a>
{% endif %}
@ -58,7 +58,7 @@
<div class="small text-muted mb-2">
Автор: {{ post.author.get_full_name|default:post.author.username }} • {{ post.created_at|date:"d.m.Y H:i" }}
</div>
<a href="{% url 'feed:post_detail' post.pk %}" class="btn btn-sm btn-outline-primary rounded-pill px-3">
<a href="{% url 'feed:post_detail' post.pk %}" class="button button--sm button--outline button--primary rounded-pill px-3">
Подробнее
</a>
</div>

View File

@ -30,7 +30,7 @@
<div class="small text-muted mb-2">
{{ post.created_at|date:"d.m.Y H:i" }}
</div>
<a href="{% url 'feed:post_detail' post.pk %}" class="btn btn-sm btn-outline-primary rounded-pill px-3">
<a href="{% url 'feed:post_detail' post.pk %}" class="button button--sm button--outline button--primary rounded-pill px-3">
Подробнее
</a>
</div>

View File

@ -15,20 +15,20 @@
<!-- Навигация и действия -->
<div class="d-flex align-items-center gap-2 mb-3">
{% if post.type == 'company' %}
<a href="{% url 'feed:feed_list' %}" class="btn btn-ghost">
<a href="{% url 'feed:feed_list' %}" class="button button--ghost">
<i class="bi-arrow-left"></i> К ленте
</a>
{% elif post.type == 'department' and dept_id %}
<a href="{% url 'employees:department_detail' dept_id %}" class="btn btn-ghost">
<a href="{% url 'employees:department_detail' dept_id %}" class="button button--ghost">
<i class="bi-arrow-left"></i> К отделу
</a>
{% else %}
{% if author_id %}
<a href="{% url 'feed:employee_feed' author_id %}" class="btn btn-ghost">
<a href="{% url 'feed:employee_feed' author_id %}" class="button button--ghost">
<i class="bi-arrow-left"></i> К публикациям автора
</a>
{% else %}
<a href="{% url 'feed:feed_list' %}" class="btn btn-ghost">
<a href="{% url 'feed:feed_list' %}" class="button button--ghost">
<i class="bi-arrow-left"></i> К ленте
</a>
{% endif %}
@ -40,16 +40,16 @@
{# Пин — без скобок в условии #}
{% if post_id %}
{% if post.type == 'company' and user.is_staff %}
<a href="{% url 'feed:pin_post' post_id %}" class="btn btn-ghost">
<a href="{% url 'feed:pin_post' post_id %}" class="button button--ghost">
<i class="bi-pin-angle"></i> {% if post.pinned %}Открепить{% else %}Закрепить{% endif %}
</a>
{% elif post.type == 'department' and dept_id %}
{% if user.is_staff %}
<a href="{% url 'feed:pin_post' post_id %}" class="btn btn-ghost">
<a href="{% url 'feed:pin_post' post_id %}" class="button button--ghost">
<i class="bi-pin-angle"></i> {% if post.pinned %}Открепить{% else %}Закрепить{% endif %}
</a>
{% elif post.department and post.department.head_id == user.id %}
<a href="{% url 'feed:pin_post' post_id %}" class="btn btn-ghost">
<a href="{% url 'feed:pin_post' post_id %}" class="button button--ghost">
<i class="bi-pin-angle"></i> {% if post.pinned %}Открепить{% else %}Закрепить{% endif %}
</a>
{% endif %}
@ -125,7 +125,7 @@
{% firstof post.attachment.url post.attachment as att_url %}
{% if att_url %}
<div class="mt-3">
<a href="{{ att_url }}" target="_blank" class="btn btn-ghost">
<a href="{{ att_url }}" target="_blank" class="button button--ghost">
<i class="bi-paperclip"></i> Вложение
</a>
</div>
@ -134,7 +134,7 @@
</div>
<footer class="card-actions">
<a href="#comments" class="btn btn-ghost">
<a href="#comments" class="button button--ghost">
<i class="bi-chat-dots"></i> Комментарии ({{ comments|length }})
</a>
@ -144,7 +144,7 @@
<form method="post" action="{% url 'feed:toggle_like' post_id %}">
{% csrf_token %}
<button type="submit"
class="btn btn-ghost {% if post.is_liked or is_liked %}is-liked{% endif %}"
class="button button--ghost {% if post.is_liked or is_liked %}is-liked{% endif %}"
data-like-post="{{ post_id }}"
data-like-url="{% url 'feed:toggle_like' post_id %}"
aria-pressed="{% if post.is_liked or is_liked %}true{% else %}false{% endif %}">
@ -217,7 +217,7 @@
{% csrf_token %}
<div class="message-field">
<textarea name="text" class="form-control message-input" rows="2" placeholder="Напишите комментарий…"></textarea>
<button class="btn btn-primary message-send" type="submit">
<button class="button button--primary message-send" type="submit">
<i class="bi-send"></i>
</button>
</div>
@ -226,7 +226,7 @@
</div>
{% else %}
<div class="text-center mt-3">
<a class="btn btn-primary" href="{% url 'auth_front:login' %}?next={{ request.path|urlencode }}">
<a class="button button--primary" href="{% url 'auth_front:login' %}?next={{ request.path|urlencode }}">
Войдите, чтобы комментировать
</a>
</div>

View File

@ -69,14 +69,14 @@
<!-- Actions: одна Отмена -->
<div class="mt-4 d-flex align-items-center gap-2">
<button type="submit" class="btn btn-success">
<button type="submit" class="button button--success">
<i class="bi-check2"></i> Сохранить
</button>
{% if cancel_url %}
<a href="{{ cancel_url }}" class="btn btn-outline-secondary">Отмена</a>
<a href="{{ cancel_url }}" class="button button--outline button--secondary">Отмена</a>
{% else %}
<a href="javascript:history.back()" class="btn btn-outline-secondary">Отмена</a>
<a href="javascript:history.back()" class="button button--outline button--secondary">Отмена</a>
{% endif %}
</div>
</div>

View File

@ -77,7 +77,7 @@
<a href="{{ yandex_disk_url }}"
target="_blank"
rel="noopener noreferrer"
class="btn btn-primary btn-lg rounded-pill px-4">
class="button button--primary button--lg rounded-pill px-4">
<i class="bi-box-arrow-up-right me-2"></i>
Открыть документ в новой вкладке
</a>

View File

@ -55,7 +55,7 @@
<div style="min-width: 100%; aspect-ratio: 16/10;"><img style="width: 100%; height: 100%; object-fit: cover; display: block;" src="https://static.insales-cdn.com/images/products/1/2793/2618977001/freepik_extend_background_to_square_canvas_naturally_keepi_23960.jpeg" alt="Фишка 15"></div>
</div>
</div>
<button id="fishka-prev-btn" style="position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; border-radius: 50%; background: rgba(255,255,255,0.95); border: none; cursor: pointer; z-index: 100; box-shadow: 0 2px 12px rgba(0,0,0,0.3); pointer-events: auto;"> </button> <button id="fishka-next-btn" style="position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; border-radius: 50%; background: rgba(255,255,255,0.95); border: none; cursor: pointer; z-index: 100; box-shadow: 0 2px 12px rgba(0,0,0,0.3); pointer-events: auto;"> </button>
<button id="fishka-prev-button" style="position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; border-radius: 50%; background: rgba(255,255,255,0.95); border: none; cursor: pointer; z-index: 100; box-shadow: 0 2px 12px rgba(0,0,0,0.3); pointer-events: auto;"> </button> <button id="fishka-next-button" style="position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; border-radius: 50%; background: rgba(255,255,255,0.95); border: none; cursor: pointer; z-index: 100; box-shadow: 0 2px 12px rgba(0,0,0,0.3); pointer-events: auto;"> </button>
<div id="fishka-dots-container" style="display: flex; gap: 10px; justify-content: center; margin-top: 20px;"></div>
</div>
</section>

View File

@ -8,7 +8,7 @@
{# Выпадающий выбор: Компания / Отделы / Личный #}
<div class="dropdown">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle text-truncate" type="button"
<button class="button button--sm button--outline button--secondary dropdown-toggle text-truncate" type="button"
id="calendarChooserBtn" data-bs-toggle="dropdown" aria-expanded="false"
style="max-width: 150px;">
Компания
@ -25,7 +25,7 @@
<div class="d-flex align-items-center gap-2 flex-shrink-0">
<span class="card-sub text-muted d-none d-xl-inline">События</span>
<button class="btn btn-sm btn-primary" type="button" data-bs-toggle="modal" data-bs-target="#eventCreateModal"
<button class="button button--sm button--primary" type="button" data-bs-toggle="modal" data-bs-target="#eventCreateModal"
aria-label="Создать событие"><i class="bi-plus-lg"></i></button>
</div>
</div>

View File

@ -8,7 +8,7 @@
{# Выпадающий выбор: Личный / Компания / Отделы #}
<div class="dropdown">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle text-truncate" type="button"
<button class="button button--sm button--outline button--secondary dropdown-toggle text-truncate" type="button"
id="calendarChooserBtnMobile" data-bs-toggle="dropdown" aria-expanded="false"
style="max-width: 120px;">
Компания
@ -24,7 +24,7 @@
</div>
<div class="d-flex align-items-center gap-2 flex-shrink-0">
<button class="btn btn-sm btn-primary" type="button" data-bs-toggle="modal" data-bs-target="#eventCreateModal"
<button class="button button--sm button--primary" type="button" data-bs-toggle="modal" data-bs-target="#eventCreateModal"
aria-label="Создать событие"><i class="bi-plus-lg"></i></button>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Закрыть"></button>
</div>

View File

@ -125,7 +125,7 @@
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Сохранить</button>
<button type="submit" class="button button--primary">Сохранить</button>
</div>
</form>
</div>

View File

@ -24,7 +24,7 @@
</dl>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
<button type="button" class="button button--secondary" data-bs-dismiss="modal">Закрыть</button>
</div>
</div>
</div>

View File

@ -3,8 +3,8 @@
{% load static %}
<div class="chat-actions-menu position-relative">
<button class="btn btn-sm btn-link text-secondary p-1" type="button"
data-chat-menu-btn
<button class="button button--sm button--link text-secondary p-1" type="button"
data-chat-menu-button
data-bs-toggle="dropdown"
data-bs-auto-close="true"
data-bs-boundary="viewport"

View File

@ -42,7 +42,7 @@
{# Кнопка раскрытия фильтров #}
{% if has_filters and filters_target %}
<button class="btn btn-outline-secondary btn-circle page-filter-toggle"
<button class="button button--outline button--secondary btn-circle page-filter-toggle"
type="button"
data-bs-toggle="collapse"
data-bs-target="#{{ filters_target }}"
@ -57,7 +57,7 @@
{% if not no_create and not create_as_card %}
{% if create_modal %}
<button type="button"
class="btn btn-primary btn-sm btn-pill btn-icon page-create-btn"
class="button button--primary button--sm btn-pill button--icon page-create-button"
data-bs-toggle="modal"
data-bs-target="#{{ create_modal }}">
<i class="{{ create_icon|default:'bi-plus-lg' }}"></i>
@ -65,7 +65,7 @@
</button>
{% elif create_url %}
<a href="{{ create_url }}"
class="btn btn-primary btn-sm btn-pill btn-icon page-create-btn">
class="button button--primary button--sm btn-pill button--icon page-create-button">
<i class="{{ create_icon|default:'bi-plus-lg' }}"></i>
<span class="btn-text">{{ create_text|default:"Создать" }}</span>
</a>

View File

@ -33,7 +33,7 @@
<!-- Уведомления: только иконка + плотный бейдж (скрыть на мобильных) -->
<div class="position-relative navbar-icon d-none d-md-block" id="notificationBell">
<button class="btn btn-link text-white p-0"
<button class="button button--link text-white p-0"
id="notificationToggle"
type="button"
title="Уведомления"
@ -82,8 +82,8 @@
</ul>
</div>
{% else %}
<a class="btn btn-outline-light rounded-pill me-2" href="{% url 'auth_front:login' %}">Войти</a>
<a class="btn btn-light rounded-pill" href="{% url 'auth_front:register' %}">Регистрация</a>
<a class="button btn-outline-light rounded-pill me-2" href="{% url 'auth_front:login' %}">Войти</a>
<a class="button button--light rounded-pill" href="{% url 'auth_front:register' %}">Регистрация</a>
{% endif %}
</div>
@ -95,7 +95,7 @@
<div class="notification-dropdown-menu" id="notificationDropdown" style="display: none;">
<div class="notification-dropdown-header">
<span class="fw-semibold">Уведомления</span>
<a href="{% url 'notifications:list' %}" class="btn btn-sm btn-link">Все</a>
<a href="{% url 'notifications:list' %}" class="button button--sm button--link">Все</a>
</div>
<div class="notification-dropdown-body" id="notificationList">
@ -108,7 +108,7 @@
<div class="notification-dropdown-divider"></div>
<div class="px-3 py-2">
<a href="{% url 'notifications:settings' %}" class="btn btn-sm btn-outline-primary w-100">
<a href="{% url 'notifications:settings' %}" class="button button--sm button--outline button--primary w-100">
<i class="bi-gear me-1"></i>Настройки уведомлений
</a>
</div>

View File

@ -70,7 +70,7 @@
</nav>
<div class="mt-auto pt-3 small">
<button type="button" class="btn-theme js-theme-btn" id="themeBtnSidebar"
<button type="button" class="btn-theme js-theme-button" id="themeBtnSidebar"
aria-label="Сменить тему" title="Сменить тему">
<i class="bi bi-circle-half" aria-hidden="true"></i>
</button>

View File

@ -12,10 +12,10 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi-bell"></i> Уведомления</h2>
<div class="btn-group">
<button id="markAllReadBtn" class="btn btn-outline-primary">
<button id="markAllReadBtn" class="button button--outline button--primary">
<i class="bi-check-all"></i> Отметить все прочитанными
</button>
<a href="{% url 'notifications:settings' %}" class="btn btn-outline-secondary">
<a href="{% url 'notifications:settings' %}" class="button button--outline button--secondary">
<i class="bi-gear"></i> Настройки
</a>
</div>
@ -52,7 +52,7 @@
<div class="input-group">
<input type="text" id="notificationSearch" class="form-control"
placeholder="Поиск по заголовку или тексту...">
<button id="searchBtn" class="btn btn-primary">
<button id="searchBtn" class="button button--primary">
<i class="bi-search"></i> Найти
</button>
</div>

View File

@ -28,7 +28,7 @@
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi-gear"></i> Настройки уведомлений</h2>
<a href="{% url 'notifications:list' %}" class="btn btn-outline-secondary">
<a href="{% url 'notifications:list' %}" class="button button--outline button--secondary">
<i class="bi-arrow-left"></i> К уведомлениям
</a>
</div>

View File

@ -28,7 +28,7 @@
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi-gear"></i> Настройки уведомлений</h2>
<a href="{% url 'notifications:list' %}" class="btn btn-outline-secondary">
<a href="{% url 'notifications:list' %}" class="button button--outline button--secondary">
<i class="bi-arrow-left"></i> К уведомлениям
</a>
</div>

View File

@ -48,10 +48,10 @@
<input type="date" name="date_to" class="form-control" value="{{ filters.date_to|default:'' }}">
</div>
<div class="col-12 col-sm-6 col-md-3 d-flex align-items-end gap-2">
<button class="btn btn-outline-primary d-flex align-items-center justify-content-center gap-1 flex-fill" type="submit">
<button class="button button--outline button--primary d-flex align-items-center justify-content-center gap-1 flex-fill" type="submit">
<i class="bi-funnel"></i><span>Применить</span>
</button>
<a class="btn btn-outline-secondary d-flex align-items-center justify-content-center" href="?" title="Сбросить фильтры">
<a class="button button--outline button--secondary d-flex align-items-center justify-content-center" href="?" title="Сбросить фильтры">
<i class="bi-x-lg"></i>
</a>
</div>

View File

@ -19,9 +19,9 @@
</dd>
<dt>Комментарий:</dt><dd>{{ request_obj.comment|default:"—" }}</dd>
</dl>
<button type="submit" class="btn btn-danger">
<button type="submit" class="button button--danger">
<i class="bi-trash"></i> Отозвать и удалить
</button>
<a href="{% url 'requests:request_list' %}" class="btn btn-outline-secondary ms-2">Отмена</a>
<a href="{% url 'requests:request_list' %}" class="button button--outline button--secondary ms-2">Отмена</a>
</form>
{% endblock %}

View File

@ -29,7 +29,7 @@
<i class="bi bi-exclamation-triangle text-warning" style="font-size: 3rem;"></i>
<h5 class="mt-3">{{ error }}</h5>
<p class="text-body-secondary">Код ошибки: {{ error_code }}</p>
<a href="{% url 'requests:request_list' %}" class="btn btn-primary mt-3">
<a href="{% url 'requests:request_list' %}" class="button button--primary mt-3">
<i class="bi-arrow-left me-2"></i>Вернуться к списку
</a>
</div>
@ -94,13 +94,13 @@
{# Кнопки действий #}
{% if can_process and request_obj.status == 'pending' %}
<div class="req-detail-actions">
<button type="button" class="btn btn-success btn-sm"
<button type="button" class="button button--success button--sm"
data-bs-toggle="modal"
data-bs-target="#reqApproveModal"
data-id="{{ request_obj.id }}">
<i class="bi-hand-thumbs-up me-1"></i>Одобрить
</button>
<button type="button" class="btn btn-danger btn-sm"
<button type="button" class="button button--danger button--sm"
data-bs-toggle="modal"
data-bs-target="#reqRejectModal"
data-id="{{ request_obj.id }}">
@ -224,7 +224,7 @@
</div>
<div class="req-info-value">
<a href="{{ request_obj.attachment_url }}" target="_blank" rel="noopener"
class="btn btn-sm btn-outline-secondary">
class="button button--sm button--outline button--secondary">
<i class="bi-download me-1"></i>Скачать
</a>
</div>
@ -256,7 +256,7 @@
{# Удаление — только автору #}
{% if c.author.id == request.user.id %}
<button class="btn btn-link btn-sm text-danger p-0 delete-comment-btn"
<button class="button button--link button--sm text-danger p-0 delete-comment-button"
type="button" title="Удалить"
data-request-id="{{ request_obj.id }}"
data-comment-id="{{ c.id }}">
@ -283,7 +283,7 @@
<div class="message-field message-field--compact">
{# Кнопка эмодзи #}
<div class="dropdown message-emoji">
<button type="button" class="btn btn-ghost btn-emoji message-icon-btn"
<button type="button" class="button button--ghost btn-emoji message-icon-button"
data-bs-toggle="dropdown" aria-expanded="false" title="Вставить смайлик">
<i class="bi-emoji-smile"></i>
</button>
@ -297,7 +297,7 @@
placeholder="Добавить комментарий..." required></textarea>
{# Кнопка отправки #}
<button type="submit" class="btn btn-primary message-send" title="Отправить">
<button type="submit" class="button button--primary message-send" title="Отправить">
<i class="bi-send"></i>
</button>
</div>
@ -331,8 +331,8 @@
</p>
</div>
<div class="modal-footer border-0">
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="btn btn-success" type="submit">
<button class="button button--secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="button button--success" type="submit">
<i class="bi-check-lg me-1"></i>Одобрить
</button>
</div>
@ -359,8 +359,8 @@
</p>
</div>
<div class="modal-footer border-0">
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="btn btn-danger" type="submit">
<button class="button button--secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="button button--danger" type="submit">
<i class="bi-x-lg me-1"></i>Отклонить
</button>
</div>
@ -383,8 +383,8 @@
if (approveModal && approveForm) {
approveModal.addEventListener('show.bs.modal', function(e) {
const btn = e.relatedTarget;
document.getElementById('approveId').value = btn?.dataset.id || requestId;
const button = e.relatedTarget;
document.getElementById('approveId').value = button?.dataset.id || requestId;
});
approveForm.addEventListener('submit', async (e) => {
@ -410,8 +410,8 @@
if (rejectModal && rejectForm) {
rejectModal.addEventListener('show.bs.modal', function(e) {
const btn = e.relatedTarget;
document.getElementById('rejectId').value = btn?.dataset.id || requestId;
const button = e.relatedTarget;
document.getElementById('rejectId').value = button?.dataset.id || requestId;
});
rejectForm.addEventListener('submit', async (e) => {
@ -486,7 +486,7 @@
// ===== Delete comments =====
document.addEventListener('click', async (e) => {
const deleteBtn = e.target.closest('.delete-comment-btn');
const deleteBtn = e.target.closest('.delete-comment-button');
if (!deleteBtn) return;
if (!confirm('Удалить комментарий?')) return;

View File

@ -12,7 +12,7 @@
<div class="section-header">
<i class="bi-clipboard-plus fs-2 text-primary"></i>
<h2 class="title mb-0">Новое заявление</h2>
<a href="{% url 'requests:request_list' %}" class="ms-auto btn btn-ghost">
<a href="{% url 'requests:request_list' %}" class="ms-auto button button--ghost">
<i class="bi-arrow-left"></i> Мои заявления
</a>
</div>
@ -35,10 +35,10 @@
{% bootstrap_form form layout="vertical" %}
<div class="d-flex gap-2 mt-2">
<button type="submit" class="btn btn-primary">
<button type="submit" class="button button--primary">
<i class="bi-check-circle"></i> Отправить заявление
</button>
<a href="{% url 'requests:request_list' %}" class="btn btn-ghost">
<a href="{% url 'requests:request_list' %}" class="button button--ghost">
Отмена
</a>
</div>

View File

@ -146,17 +146,17 @@
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="button button--secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<!-- Новая кнопка: сохранить как черновик -->
<!-- formnovalidate позволяет сохранить не заполняя обязательные поля -->
<button class="btn btn-outline-secondary" type="submit"
<button class="button button--outline button--secondary" type="submit"
name="_save_as" value="draft" formnovalidate>
Сохранить как черновик
</button>
<!-- Обычное создание -->
<button class="btn btn-primary" type="submit" name="_save_as" value="submit">
<button class="button button--primary" type="submit" name="_save_as" value="submit">
Создать
</button>
</div>
@ -237,8 +237,8 @@
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="btn btn-primary" type="submit">Сохранить</button>
<button class="button button--secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="button button--primary" type="submit">Сохранить</button>
</div>
</form>
</div>
@ -259,8 +259,8 @@
Это действие необратимо.
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="btn btn-danger" type="submit">Удалить</button>
<button class="button button--secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="button button--danger" type="submit">Удалить</button>
</div>
</form>
</div>
@ -277,8 +277,8 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="btn btn-success" type="submit">Одобрить</button>
<button class="button button--secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="button button--success" type="submit">Одобрить</button>
</div>
</form>
</div>
@ -295,7 +295,7 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
</div>
<div class="modal-footer">
<button class="btn btn-danger" type="submit">Отклонить</button>
<button class="button button--danger" type="submit">Отклонить</button>
</div>
</form>
</div>
@ -312,8 +312,8 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="btn btn-outline-secondary" type="submit">Отменить</button>
<button class="button button--secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="button button--outline button--secondary" type="submit">Отменить</button>
</div>
</form>
</div>
@ -335,8 +335,8 @@
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="btn btn-primary" type="submit">Отправить</button>
<button class="button button--secondary" type="button" data-bs-dismiss="modal">Отмена</button>
<button class="button button--primary" type="submit">Отправить</button>
</div>
</form>
</div>
@ -368,8 +368,8 @@
{% endif %}
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#reqCommentModal"
<button class="button button--secondary" data-bs-dismiss="modal">Закрыть</button>
<button class="button button--primary" data-bs-toggle="modal" data-bs-target="#reqCommentModal"
data-id="{{ comments_for }}">Добавить комментарий</button>
</div>
</div>

View File

@ -14,7 +14,7 @@
<i class="bi-clipboard-check fs-2 text-primary"></i>
<h2 class="title mb-0">Рассмотрение заявления</h2>
<div class="ms-auto">
<a href="{% url 'requests:request_list' %}" class="btn btn-ghost">
<a href="{% url 'requests:request_list' %}" class="button button--ghost">
<i class="bi-arrow-left"></i> К списку
</a>
</div>
@ -85,7 +85,7 @@
{# Вложение сотрудника (если есть) #}
{% if request_obj.attachment_url %}
<a class="btn btn-ghost d-inline-flex align-items-center gap-1"
<a class="button button--ghost d-inline-flex align-items-center gap-1"
href="{{ request_obj.attachment_url }}" target="_blank"
rel="noopener noreferrer" download>
<i class="bi-paperclip"></i><span>Вложение сотрудника</span>
@ -132,10 +132,10 @@
{% bootstrap_form form %}
<div class="d-flex gap-2 mt-2">
<button type="submit" class="btn btn-primary">
<button type="submit" class="button button--primary">
<i class="bi-check-circle"></i> Сохранить решение
</button>
<a href="{% url 'requests:request_list' %}" class="btn btn-ghost">
<a href="{% url 'requests:request_list' %}" class="button button--ghost">
Отмена
</a>
</div>
@ -178,7 +178,7 @@
action="{% url 'requests_app:request_comment_delete' request_obj.pk c.pk %}?next={{ request.get_full_path|urlencode }}#comments"
onsubmit="return confirm('Удалить комментарий №{{ c.pk }}?');">
{% csrf_token %}
<button class="btn btn-sm btn-ghost text-danger" type="submit" title="Удалить">
<button class="button button--sm button--ghost text-danger" type="submit" title="Удалить">
<i class="bi-trash"></i>
</button>
</form>
@ -199,7 +199,7 @@
<div class="message-field message-field--compact">
<!-- Кнопка выбора эмодзи -->
<div class="dropdown message-emoji">
<button type="button" class="btn btn-ghost btn-emoji message-icon-btn"
<button type="button" class="button button--ghost btn-emoji message-icon-button"
data-bs-toggle="dropdown"
aria-expanded="false"
title="Вставить смайлик">
@ -212,7 +212,7 @@
<textarea name="text" class="form-control message-input" rows="1"
placeholder="Оставить комментарий…"
maxlength="{{ max_comment_len|default:1000 }}"></textarea>
<button class="btn btn-primary message-send" type="submit" title="Отправить">
<button class="button button--primary message-send" type="submit" title="Отправить">
<i class="bi-send"></i>
</button>
</div>
@ -272,14 +272,14 @@
// Показываем успех
submitBtn.disabled = false;
submitBtn.innerHTML = '<i class="bi-check-circle"></i> ✓ Сохранено';
submitBtn.classList.add('btn-success');
submitBtn.classList.remove('btn-primary');
submitBtn.classList.add('button--success');
submitBtn.classList.remove('button--primary');
// Возвращаем кнопку в исходное состояние через 2 секунды
setTimeout(() => {
submitBtn.innerHTML = originalText;
submitBtn.classList.remove('btn-success');
submitBtn.classList.add('btn-primary');
submitBtn.classList.remove('button--success');
submitBtn.classList.add('button--primary');
}, 2000);
// Прокручиваем вверх к результату

View File

@ -14,10 +14,10 @@
</select>
</div>
<div class="col-12 col-sm-3 d-flex justify-content-end gap-2">
<button class="btn btn-outline-primary d-flex align-items-center justify-content-center gap-1" type="button" id="applySearchFilter">
<button class="button button--outline button--primary d-flex align-items-center justify-content-center gap-1" type="button" id="applySearchFilter">
<i class="bi-funnel"></i><span>Применить</span>
</button>
<button type="button" class="btn btn-outline-secondary d-flex align-items-center justify-content-center" id="resetSearchFilter" title="Сбросить фильтры">
<button type="button" class="button button--outline button--secondary d-flex align-items-center justify-content-center" id="resetSearchFilter" title="Сбросить фильтры">
<i class="bi-x-lg"></i>
</button>
</div>