mirror of
https://github.com/asyouplz/SpeechNote.git
synced 2026-07-22 06:43:33 +00:00
fix(ui): namespace review-target css selectors (#84)
This commit is contained in:
parent
77b63f54b3
commit
1b0c80b0ad
16 changed files with 1394 additions and 1394 deletions
|
|
@ -130,7 +130,7 @@ describe('NotificationManager', () => {
|
|||
|
||||
// DOM에서 확인 버튼 찾기
|
||||
setTimeout(() => {
|
||||
const confirmBtn = document.querySelector('.modal__action--primary') as HTMLElement;
|
||||
const confirmBtn = document.querySelector('.sn-modal__action--primary') as HTMLElement;
|
||||
confirmBtn?.click();
|
||||
}, 10);
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ describe('NotificationManager', () => {
|
|||
|
||||
// DOM에서 확인 버튼 찾기
|
||||
setTimeout(() => {
|
||||
const okBtn = document.querySelector('.modal__action--primary') as HTMLElement;
|
||||
const okBtn = document.querySelector('.sn-modal__action--primary') as HTMLElement;
|
||||
okBtn?.click();
|
||||
}, 10);
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ describe('NotificationManager', () => {
|
|||
progress.update(50, 'Halfway there');
|
||||
|
||||
// DOM 확인
|
||||
const toastEl = document.querySelector('.toast');
|
||||
const toastEl = document.querySelector('.sn-toast');
|
||||
expect(toastEl).toBeDefined();
|
||||
});
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ describe('NotificationManager', () => {
|
|||
progress.complete('Done!');
|
||||
|
||||
// DOM 확인
|
||||
const toastEl = document.querySelector('.toast--success');
|
||||
const toastEl = document.querySelector('.sn-toast--success');
|
||||
expect(toastEl).toBeDefined();
|
||||
});
|
||||
|
||||
|
|
@ -191,7 +191,7 @@ describe('NotificationManager', () => {
|
|||
progress.error('Failed to load');
|
||||
|
||||
// DOM 확인
|
||||
const toastEl = document.querySelector('.toast--error');
|
||||
const toastEl = document.querySelector('.sn-toast--error');
|
||||
expect(toastEl).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -293,17 +293,17 @@ describe('NotificationManager', () => {
|
|||
it('Toast 컨테이너를 생성해야 함', () => {
|
||||
manager.info('Test');
|
||||
|
||||
const container = document.querySelector('.toast-container');
|
||||
const container = document.querySelector('.sn-toast-container');
|
||||
expect(container).toBeDefined();
|
||||
});
|
||||
|
||||
it('Toast 요소를 생성해야 함', () => {
|
||||
manager.info('Test message');
|
||||
|
||||
const toast = document.querySelector('.toast');
|
||||
const toast = document.querySelector('.sn-toast');
|
||||
expect(toast).toBeDefined();
|
||||
|
||||
const message = toast?.querySelector('.toast__message');
|
||||
const message = toast?.querySelector('.sn-toast__message');
|
||||
expect(message?.textContent).toBe('Test message');
|
||||
});
|
||||
|
||||
|
|
@ -316,7 +316,7 @@ describe('NotificationManager', () => {
|
|||
|
||||
// urgent priority는 Modal을 사용
|
||||
setTimeout(() => {
|
||||
const overlay = document.querySelector('.modal-overlay');
|
||||
const overlay = document.querySelector('.sn-modal-overlay');
|
||||
expect(overlay).toBeDefined();
|
||||
}, 10);
|
||||
});
|
||||
|
|
@ -329,7 +329,7 @@ describe('NotificationManager', () => {
|
|||
});
|
||||
|
||||
// low priority는 StatusBar를 사용
|
||||
const statusBar = document.querySelector('.status-bar');
|
||||
const statusBar = document.querySelector('.sn-status-bar');
|
||||
expect(statusBar).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -190,10 +190,10 @@ export class DragDropZone {
|
|||
|
||||
if (this.dropZone) {
|
||||
if (isDragging) {
|
||||
this.dropZone.addClass('is-dragging');
|
||||
this.dropZone.addClass('sn-is-dragging');
|
||||
this.showDragOverlay();
|
||||
} else {
|
||||
this.dropZone.removeClass('is-dragging');
|
||||
this.dropZone.removeClass('sn-is-dragging');
|
||||
this.hideDragOverlay();
|
||||
}
|
||||
}
|
||||
|
|
@ -216,7 +216,7 @@ export class DragDropZone {
|
|||
icon.appendChild(this.createDropIcon());
|
||||
content.createDiv('sn-drag-overlay-text').setText('Drop files to add them');
|
||||
}
|
||||
overlay.addClass('is-active');
|
||||
overlay.addClass('sn-is-active');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -225,7 +225,7 @@ export class DragDropZone {
|
|||
private hideDragOverlay() {
|
||||
const overlay = this.dropZone?.querySelector('.sn-drag-overlay');
|
||||
if (overlay instanceof HTMLElement) {
|
||||
overlay.removeClass('is-active');
|
||||
overlay.removeClass('sn-is-active');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +324,7 @@ export class DragDropZone {
|
|||
private showMessage(message: string, type: 'success' | 'error') {
|
||||
if (!this.dropZone) return;
|
||||
|
||||
const messageEl = this.dropZone.createDiv(`sn-drop-zone-message ${type}`);
|
||||
const messageEl = this.dropZone.createDiv(`sn-drop-zone-message sn-drop-zone-message--${type}`);
|
||||
messageEl.setText(message);
|
||||
|
||||
setTimeout(() => {
|
||||
|
|
|
|||
|
|
@ -176,10 +176,10 @@ export class FileBrowser {
|
|||
isExpanded = !isExpanded;
|
||||
if (isExpanded) {
|
||||
fileList.show();
|
||||
folderHeader.removeClass('collapsed');
|
||||
folderHeader.removeClass('sn-is-collapsed');
|
||||
} else {
|
||||
fileList.hide();
|
||||
folderHeader.addClass('is-collapsed');
|
||||
folderHeader.addClass('sn-is-collapsed');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -225,12 +225,12 @@ export class FileBrowser {
|
|||
// 클릭 이벤트
|
||||
fileItem.addEventListener('click', () => {
|
||||
this.selectFile(file);
|
||||
fileItem.addClass('is-selected');
|
||||
fileItem.addClass('sn-is-selected');
|
||||
|
||||
// 다른 선택 해제
|
||||
container.querySelectorAll('.sn-file-item').forEach((item) => {
|
||||
if (item !== fileItem) {
|
||||
item.removeClass('is-selected');
|
||||
item.removeClass('sn-is-selected');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ export class ProgressIndicator {
|
|||
}
|
||||
if (spinner instanceof HTMLElement) {
|
||||
spinner.addClass('sn-hidden');
|
||||
spinner.removeClass('is-spinning');
|
||||
spinner.removeClass('sn-is-spinning');
|
||||
}
|
||||
this.update(0);
|
||||
} else {
|
||||
|
|
@ -172,13 +172,13 @@ export class ProgressIndicator {
|
|||
|
||||
// 진행률에 따른 색상 변경
|
||||
if (this.currentProgress < 30) {
|
||||
progressFill.removeClass('is-warning', 'is-success');
|
||||
progressFill.removeClass('sn-is-warning', 'sn-is-success');
|
||||
} else if (this.currentProgress < 70) {
|
||||
progressFill.addClass('is-warning');
|
||||
progressFill.removeClass('is-success');
|
||||
progressFill.addClass('sn-is-warning');
|
||||
progressFill.removeClass('sn-is-success');
|
||||
} else {
|
||||
progressFill.removeClass('is-warning');
|
||||
progressFill.addClass('is-success');
|
||||
progressFill.removeClass('sn-is-warning');
|
||||
progressFill.addClass('sn-is-success');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +241,7 @@ export class ProgressIndicator {
|
|||
|
||||
const content = this.progressElement.querySelector('.sn-progress-content');
|
||||
if (content instanceof HTMLElement) {
|
||||
content.addClass('is-error');
|
||||
content.addClass('sn-is-error');
|
||||
|
||||
// 스피너를 에러 아이콘으로 변경
|
||||
const spinner = content.querySelector('.sn-progress-spinner');
|
||||
|
|
@ -264,7 +264,7 @@ export class ProgressIndicator {
|
|||
|
||||
const content = this.progressElement.querySelector('.sn-progress-content');
|
||||
if (content instanceof HTMLElement) {
|
||||
content.addClass('is-success');
|
||||
content.addClass('sn-is-success');
|
||||
|
||||
// 스피너를 성공 아이콘으로 변경
|
||||
const spinner = content.querySelector('.sn-progress-spinner');
|
||||
|
|
@ -290,7 +290,7 @@ export class ProgressIndicator {
|
|||
private startSpinnerAnimation() {
|
||||
const spinner = this.progressElement?.querySelector('.sn-progress-spinner');
|
||||
if (spinner instanceof HTMLElement) {
|
||||
spinner.addClass('is-spinning');
|
||||
spinner.addClass('sn-is-spinning');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ export class ProgressIndicator {
|
|||
private stopSpinnerAnimation() {
|
||||
const spinner = this.progressElement?.querySelector('.sn-progress-spinner');
|
||||
if (spinner instanceof HTMLElement) {
|
||||
spinner.removeClass('is-spinning');
|
||||
spinner.removeClass('sn-is-spinning');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,12 +50,12 @@ export class RecentFiles {
|
|||
this.container.addClass('sn-recent-files');
|
||||
|
||||
// 헤더
|
||||
const header = this.container.createDiv('recent-files-header');
|
||||
const header = this.container.createDiv('sn-recent-files-header');
|
||||
header.createEl('h3', { text: 'Recent files' });
|
||||
|
||||
// 초기화 버튼
|
||||
const clearBtn = header.createEl('button', {
|
||||
cls: 'clear-recent-btn',
|
||||
cls: 'sn-clear-recent-btn',
|
||||
text: 'Clear',
|
||||
title: 'Clear recent files',
|
||||
});
|
||||
|
|
@ -86,7 +86,7 @@ export class RecentFiles {
|
|||
|
||||
if (validFiles.length === 0) {
|
||||
listContainer.createDiv({
|
||||
cls: 'empty-state',
|
||||
cls: 'sn-empty-state',
|
||||
text: 'No recent files',
|
||||
});
|
||||
return;
|
||||
|
|
@ -156,7 +156,7 @@ export class RecentFiles {
|
|||
|
||||
// 선택 버튼
|
||||
const selectBtn = actions.createEl('button', {
|
||||
cls: 'select-btn',
|
||||
cls: 'sn-select-btn',
|
||||
title: 'Select file',
|
||||
});
|
||||
setIcon(selectBtn, 'check');
|
||||
|
|
@ -169,7 +169,7 @@ export class RecentFiles {
|
|||
|
||||
// 제거 버튼
|
||||
const removeBtn = actions.createEl('button', {
|
||||
cls: 'remove-btn',
|
||||
cls: 'sn-remove-btn',
|
||||
title: 'Remove from list',
|
||||
});
|
||||
setIcon(removeBtn, 'x');
|
||||
|
|
@ -187,7 +187,7 @@ export class RecentFiles {
|
|||
|
||||
// 파일이 존재하지 않는 경우 표시
|
||||
if (!this.app.vault.getAbstractFileByPath(entry.path)) {
|
||||
fileItem.addClass('file-not-found');
|
||||
fileItem.addClass('sn-is-file-not-found');
|
||||
fileName.setText(`${file.basename} (Not found)`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ export class StatisticsDashboard {
|
|||
};
|
||||
|
||||
Object.entries(updates).forEach(([id, value]) => {
|
||||
const card = this.element?.querySelector(`[data-stat-id="${id}"] .stats-card__value`);
|
||||
const card = this.element?.querySelector(`[data-stat-id="${id}"] .sn-stats-card__value`);
|
||||
if (card) {
|
||||
card.textContent = value;
|
||||
}
|
||||
|
|
@ -506,7 +506,7 @@ export class StatisticsDashboard {
|
|||
});
|
||||
bar.appendChild(valueLabel);
|
||||
|
||||
const barLabel = createEl('span', { cls: 'bar-chart__label', text: `${hour}:00` });
|
||||
const barLabel = createEl('span', { cls: 'sn-bar-chart__label', text: `${hour}:00` });
|
||||
bar.appendChild(barLabel);
|
||||
|
||||
chartContainer.appendChild(bar);
|
||||
|
|
@ -624,7 +624,7 @@ export class StatisticsDashboard {
|
|||
row.appendChild(wordCountCell);
|
||||
|
||||
const actionCell = createEl('td');
|
||||
const actionBtn = createEl('button', { cls: 'action-btn', text: 'View' });
|
||||
const actionBtn = createEl('button', { cls: 'sn-action-btn', text: 'View' });
|
||||
actionBtn.dataset.recordId = record.id;
|
||||
actionBtn.dataset.action = 'view';
|
||||
actionBtn.addEventListener('click', () => {
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ export class FilePickerModal extends Modal {
|
|||
}
|
||||
|
||||
// 모달 클래스 추가
|
||||
this.modalEl?.classList?.add('file-picker-modal');
|
||||
this.modalEl?.classList?.add('sn-file-picker-modal');
|
||||
this.modalEl?.classList?.add('speech-to-text-modal');
|
||||
}
|
||||
|
||||
|
|
@ -149,17 +149,17 @@ export class FilePickerModal extends Modal {
|
|||
}
|
||||
|
||||
// 탭 컨테이너
|
||||
const tabContainer = contentEl.createDiv('file-picker-tabs');
|
||||
const tabContainer = contentEl.createDiv('sn-file-picker-tabs');
|
||||
|
||||
// 탭 헤더
|
||||
const tabHeader = tabContainer.createDiv('tab-header');
|
||||
const tabHeader = tabContainer.createDiv('sn-tab-header');
|
||||
const browseTab = this.createTab(tabHeader, 'Browse', true);
|
||||
const recentTab = this.options.showRecentFiles
|
||||
? this.createTab(tabHeader, 'Recent', false)
|
||||
: null;
|
||||
|
||||
// 탭 콘텐츠
|
||||
const tabContent = tabContainer.createDiv('tab-content');
|
||||
const tabContent = tabContainer.createDiv('sn-tab-content');
|
||||
const browseContent = this.createBrowseContent(tabContent);
|
||||
const recentContent = this.options.showRecentFiles
|
||||
? this.createRecentContent(tabContent)
|
||||
|
|
@ -182,10 +182,10 @@ export class FilePickerModal extends Modal {
|
|||
}
|
||||
|
||||
private createHeader(container: HTMLElement) {
|
||||
const header = container.createDiv('file-picker-header');
|
||||
const header = container.createDiv('sn-file-picker-header');
|
||||
header.createEl('h2', { text: this.options.title });
|
||||
|
||||
const subtitle = header.createEl('p', { cls: 'file-picker-subtitle' });
|
||||
const subtitle = header.createEl('p', { cls: 'sn-file-picker-subtitle' });
|
||||
if (this.options.accept.length > 0) {
|
||||
subtitle.setText(
|
||||
`Supported formats: ${this.options.accept.map((ext) => `.${ext}`).join(', ')}`
|
||||
|
|
@ -201,7 +201,7 @@ export class FilePickerModal extends Modal {
|
|||
private createDragDropSection(container: HTMLElement) {
|
||||
if (!this.dragDropZone) return;
|
||||
|
||||
const dropSection = container.createDiv('drag-drop-section');
|
||||
const dropSection = container.createDiv('sn-drag-drop-section');
|
||||
|
||||
this.dragDropZone.mount(dropSection);
|
||||
this.dragDropZone.onFilesDropped((files) => {
|
||||
|
|
@ -210,7 +210,7 @@ export class FilePickerModal extends Modal {
|
|||
}
|
||||
|
||||
private createBrowseContent(container: HTMLElement): HTMLElement {
|
||||
const browseContent = container.createDiv('browse-content active');
|
||||
const browseContent = container.createDiv('sn-browse-content sn-is-active');
|
||||
|
||||
// 파일 브라우저 마운트
|
||||
this.fileBrowser.mount(browseContent);
|
||||
|
|
@ -224,7 +224,7 @@ export class FilePickerModal extends Modal {
|
|||
}
|
||||
|
||||
private createRecentContent(container: HTMLElement): HTMLElement {
|
||||
const recentContent = container.createDiv('recent-content');
|
||||
const recentContent = container.createDiv('sn-recent-content');
|
||||
|
||||
if (this.recentFiles) {
|
||||
this.recentFiles.mount(recentContent);
|
||||
|
|
@ -239,10 +239,10 @@ export class FilePickerModal extends Modal {
|
|||
}
|
||||
|
||||
private createSelectedFilesSection(container: HTMLElement) {
|
||||
const section = container.createDiv('selected-files-section');
|
||||
const section = container.createDiv('sn-selected-files-section');
|
||||
section.createEl('h3', { text: 'Selected files' });
|
||||
|
||||
const fileList = section.createDiv('selected-files-list');
|
||||
const fileList = section.createDiv('sn-selected-files-list');
|
||||
this.updateSelectedFilesList(fileList);
|
||||
}
|
||||
|
||||
|
|
@ -252,31 +252,31 @@ export class FilePickerModal extends Modal {
|
|||
if (this.selectedFiles.length === 0) {
|
||||
container.createEl('p', {
|
||||
text: 'No files selected',
|
||||
cls: 'no-files-message',
|
||||
cls: 'sn-no-files-message',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedFiles.forEach((file) => {
|
||||
const fileItem = container.createDiv('selected-file-item');
|
||||
const fileItem = container.createDiv('sn-selected-file-item');
|
||||
|
||||
// 파일 정보
|
||||
const fileInfo = fileItem.createDiv('file-info');
|
||||
fileInfo.createEl('span', { text: file.name, cls: 'file-name' });
|
||||
const fileInfo = fileItem.createDiv('sn-file-info');
|
||||
fileInfo.createEl('span', { text: file.name, cls: 'sn-file-name' });
|
||||
fileInfo.createEl('span', {
|
||||
text: this.formatFileSize(file.stat.size),
|
||||
cls: 'file-size',
|
||||
cls: 'sn-file-size',
|
||||
});
|
||||
|
||||
// 검증 상태
|
||||
const validation = this.validationResults.get(file.path);
|
||||
if (validation) {
|
||||
const statusIcon = fileItem.createDiv('validation-status');
|
||||
const statusIcon = fileItem.createDiv('sn-validation-status');
|
||||
if (validation.valid) {
|
||||
statusIcon.addClass('valid');
|
||||
statusIcon.addClass('sn-is-valid');
|
||||
statusIcon.setText('✓');
|
||||
} else {
|
||||
statusIcon.addClass('invalid');
|
||||
statusIcon.addClass('sn-is-invalid');
|
||||
statusIcon.setText('✗');
|
||||
statusIcon.title =
|
||||
validation.errors?.map((error) => error.message).join('\n') || '';
|
||||
|
|
@ -286,7 +286,7 @@ export class FilePickerModal extends Modal {
|
|||
// 제거 버튼
|
||||
const removeBtn = fileItem.createEl('button', {
|
||||
text: 'Remove',
|
||||
cls: 'remove-file-btn',
|
||||
cls: 'sn-remove-file-btn',
|
||||
});
|
||||
removeBtn.onclick = () => {
|
||||
this.removeFile(file);
|
||||
|
|
@ -296,7 +296,7 @@ export class FilePickerModal extends Modal {
|
|||
}
|
||||
|
||||
private createFooter(container: HTMLElement) {
|
||||
const footer = container.createDiv('file-picker-footer');
|
||||
const footer = container.createDiv('sn-file-picker-footer');
|
||||
|
||||
new Setting(footer)
|
||||
.addButton((btn) =>
|
||||
|
|
@ -438,7 +438,7 @@ export class FilePickerModal extends Modal {
|
|||
|
||||
private createTab(container: HTMLElement, label: string, active: boolean): HTMLElement {
|
||||
const tab = container.createDiv({
|
||||
cls: `tab-button ${active ? 'active' : ''}`,
|
||||
cls: `sn-tab-button ${active ? 'sn-is-active' : ''}`,
|
||||
text: label,
|
||||
});
|
||||
return tab;
|
||||
|
|
@ -451,21 +451,21 @@ export class FilePickerModal extends Modal {
|
|||
recentContent: HTMLElement | null
|
||||
) {
|
||||
browseTab.onclick = () => {
|
||||
browseTab.addClass('active');
|
||||
browseContent.addClass('active');
|
||||
browseTab.addClass('sn-is-active');
|
||||
browseContent.addClass('sn-is-active');
|
||||
|
||||
if (recentTab && recentContent) {
|
||||
recentTab.removeClass('active');
|
||||
recentContent.removeClass('active');
|
||||
recentTab.removeClass('sn-is-active');
|
||||
recentContent.removeClass('sn-is-active');
|
||||
}
|
||||
};
|
||||
|
||||
if (recentTab && recentContent) {
|
||||
recentTab.onclick = () => {
|
||||
recentTab.addClass('active');
|
||||
recentContent.addClass('active');
|
||||
browseTab.removeClass('active');
|
||||
browseContent.removeClass('active');
|
||||
recentTab.addClass('sn-is-active');
|
||||
recentContent.addClass('sn-is-active');
|
||||
browseTab.removeClass('sn-is-active');
|
||||
browseContent.removeClass('sn-is-active');
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -484,7 +484,7 @@ export class FilePickerModal extends Modal {
|
|||
}
|
||||
|
||||
private refreshUI() {
|
||||
const selectedSection = this.modalEl.querySelector('.selected-files-list');
|
||||
const selectedSection = this.modalEl.querySelector('.sn-selected-files-list');
|
||||
if (selectedSection instanceof HTMLElement) {
|
||||
this.updateSelectedFilesList(selectedSection);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ export class FilePickerModalRefactored extends Modal {
|
|||
* 모달 설정 - 단일 책임
|
||||
*/
|
||||
private setupModal(): void {
|
||||
this.modalEl.addClass('file-picker-modal', 'speech-to-text-modal');
|
||||
this.modalEl.addClass('sn-file-picker-modal', 'speech-to-text-modal');
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
|
|
@ -219,16 +219,16 @@ export class FilePickerModalRefactored extends Modal {
|
|||
|
||||
// Remove all active classes
|
||||
[browseTab, browseContent, recentTab, recentContent].forEach((el) => {
|
||||
el?.removeClass('active');
|
||||
el?.removeClass('sn-is-active');
|
||||
});
|
||||
|
||||
// Add active class to selected tab
|
||||
if (tab === 'browse') {
|
||||
browseTab.addClass('active');
|
||||
browseContent.addClass('active');
|
||||
browseTab.addClass('sn-is-active');
|
||||
browseContent.addClass('sn-is-active');
|
||||
} else if (recentTab && recentContent) {
|
||||
recentTab.addClass('active');
|
||||
recentContent.addClass('active');
|
||||
recentTab.addClass('sn-is-active');
|
||||
recentContent.addClass('sn-is-active');
|
||||
}
|
||||
|
||||
this.state.activeTab = tab;
|
||||
|
|
@ -509,7 +509,7 @@ export class FilePickerModalRefactored extends Modal {
|
|||
private refreshUI(): void {
|
||||
requestAnimationFrame(() => {
|
||||
// Update selected files list
|
||||
const listContainer = this.modalEl.querySelector('.selected-files-list');
|
||||
const listContainer = this.modalEl.querySelector('.sn-selected-files-list');
|
||||
if (listContainer instanceof HTMLElement) {
|
||||
this.updateSelectedFilesList(listContainer);
|
||||
}
|
||||
|
|
@ -621,10 +621,10 @@ class FilePickerUIBuilder {
|
|||
) {}
|
||||
|
||||
buildHeader(): void {
|
||||
const header = this.container.createDiv('file-picker-header');
|
||||
const header = this.container.createDiv('sn-file-picker-header');
|
||||
header.createEl('h2', { text: this.options.title });
|
||||
|
||||
const subtitle = header.createEl('p', { cls: 'file-picker-subtitle' });
|
||||
const subtitle = header.createEl('p', { cls: 'sn-file-picker-subtitle' });
|
||||
this.buildSubtitle(subtitle);
|
||||
}
|
||||
|
||||
|
|
@ -647,20 +647,20 @@ class FilePickerUIBuilder {
|
|||
buildDragDropSection(): void {
|
||||
if (!this.options.enableDragDrop || !this.components.dragDropZone) return;
|
||||
|
||||
const dropSection = this.container.createDiv('drag-drop-section');
|
||||
const dropSection = this.container.createDiv('sn-drag-drop-section');
|
||||
this.components.dragDropZone.mount(dropSection);
|
||||
}
|
||||
|
||||
buildTabContainer(): TabContainer {
|
||||
const tabContainer = this.container.createDiv('file-picker-tabs');
|
||||
const tabHeader = tabContainer.createDiv('tab-header');
|
||||
const tabContainer = this.container.createDiv('sn-file-picker-tabs');
|
||||
const tabHeader = tabContainer.createDiv('sn-tab-header');
|
||||
|
||||
const browseTab = this.createTab(tabHeader, 'Browse', true);
|
||||
const recentTab = this.options.showRecentFiles
|
||||
? this.createTab(tabHeader, 'Recent', false)
|
||||
: null;
|
||||
|
||||
const tabContent = tabContainer.createDiv('tab-content');
|
||||
const tabContent = tabContainer.createDiv('sn-tab-content');
|
||||
const browseContent = this.createBrowseContent(tabContent);
|
||||
const recentContent = this.options.showRecentFiles
|
||||
? this.createRecentContent(tabContent)
|
||||
|
|
@ -671,19 +671,19 @@ class FilePickerUIBuilder {
|
|||
|
||||
private createTab(container: HTMLElement, label: string, active: boolean): HTMLElement {
|
||||
return container.createDiv({
|
||||
cls: `tab-button ${active ? 'active' : ''}`,
|
||||
cls: `sn-tab-button ${active ? 'sn-is-active' : ''}`,
|
||||
text: label,
|
||||
});
|
||||
}
|
||||
|
||||
private createBrowseContent(container: HTMLElement): HTMLElement {
|
||||
const content = container.createDiv('browse-content active');
|
||||
const content = container.createDiv('sn-browse-content sn-is-active');
|
||||
this.components.fileBrowser.mount(content);
|
||||
return content;
|
||||
}
|
||||
|
||||
private createRecentContent(container: HTMLElement): HTMLElement {
|
||||
const content = container.createDiv('recent-content');
|
||||
const content = container.createDiv('sn-recent-content');
|
||||
if (this.components.recentFiles) {
|
||||
this.components.recentFiles.mount(content);
|
||||
}
|
||||
|
|
@ -691,10 +691,10 @@ class FilePickerUIBuilder {
|
|||
}
|
||||
|
||||
buildSelectedFilesSection(updateCallback: (container: HTMLElement) => void): void {
|
||||
const section = this.container.createDiv('selected-files-section');
|
||||
const section = this.container.createDiv('sn-selected-files-section');
|
||||
section.createEl('h3', { text: 'Selected files' });
|
||||
|
||||
const fileList = section.createDiv('selected-files-list');
|
||||
const fileList = section.createDiv('sn-selected-files-list');
|
||||
updateCallback(fileList);
|
||||
}
|
||||
|
||||
|
|
@ -703,7 +703,7 @@ class FilePickerUIBuilder {
|
|||
}
|
||||
|
||||
buildFooter(onCancel: () => void, onSubmit: () => void, fileCount: number): void {
|
||||
const footer = this.container.createDiv('file-picker-footer');
|
||||
const footer = this.container.createDiv('sn-file-picker-footer');
|
||||
|
||||
new Setting(footer)
|
||||
.addButton((btn) => btn.setButtonText('Cancel').onClick(onCancel))
|
||||
|
|
@ -739,7 +739,7 @@ class SelectedFilesListRenderer {
|
|||
}
|
||||
|
||||
private renderFileItem(file: TFile): void {
|
||||
const fileItem = this.container.createDiv('selected-file-item');
|
||||
const fileItem = this.container.createDiv('sn-selected-file-item');
|
||||
|
||||
this.renderFileInfo(fileItem, file);
|
||||
this.renderValidationStatus(fileItem, file);
|
||||
|
|
@ -747,11 +747,11 @@ class SelectedFilesListRenderer {
|
|||
}
|
||||
|
||||
private renderFileInfo(container: HTMLElement, file: TFile): void {
|
||||
const fileInfo = container.createDiv('file-info');
|
||||
fileInfo.createEl('span', { text: file.name, cls: 'file-name' });
|
||||
const fileInfo = container.createDiv('sn-file-info');
|
||||
fileInfo.createEl('span', { text: file.name, cls: 'sn-file-name' });
|
||||
fileInfo.createEl('span', {
|
||||
text: this.formatFileSize(file.stat.size),
|
||||
cls: 'file-size',
|
||||
cls: 'sn-file-size',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -759,13 +759,13 @@ class SelectedFilesListRenderer {
|
|||
const validation = this.validationResults.get(file.path);
|
||||
if (!validation) return;
|
||||
|
||||
const statusIcon = container.createDiv('validation-status');
|
||||
const statusIcon = container.createDiv('sn-validation-status');
|
||||
|
||||
if (validation.valid) {
|
||||
statusIcon.addClass('valid');
|
||||
statusIcon.addClass('sn-is-valid');
|
||||
statusIcon.setText('✓');
|
||||
} else {
|
||||
statusIcon.addClass('invalid');
|
||||
statusIcon.addClass('sn-is-invalid');
|
||||
statusIcon.setText('✗');
|
||||
statusIcon.title = validation.errors?.map((error) => error.message).join('\n') || '';
|
||||
}
|
||||
|
|
@ -774,7 +774,7 @@ class SelectedFilesListRenderer {
|
|||
private renderRemoveButton(container: HTMLElement, file: TFile): void {
|
||||
const removeBtn = container.createEl('button', {
|
||||
text: 'Remove',
|
||||
cls: 'remove-file-btn',
|
||||
cls: 'sn-remove-file-btn',
|
||||
});
|
||||
|
||||
removeBtn.onclick = () => this.onRemove(file);
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export class ToastNotification {
|
|||
private static initContainer(position: NotificationPosition = 'top-right') {
|
||||
if (!this.container) {
|
||||
this.container = createEl('div', {
|
||||
cls: `toast-container toast-container--${position}`,
|
||||
cls: `sn-toast-container sn-toast-container--${position}`,
|
||||
attr: {
|
||||
role: 'region',
|
||||
'aria-label': 'Notification area',
|
||||
|
|
@ -80,7 +80,7 @@ export class ToastNotification {
|
|||
document.body.appendChild(this.container);
|
||||
} else {
|
||||
// 위치 변경
|
||||
this.container.className = `toast-container toast-container--${position}`;
|
||||
this.container.className = `sn-toast-container sn-toast-container--${position}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ export class ToastNotification {
|
|||
|
||||
// Toast 요소 생성
|
||||
const toast = createEl('div', {
|
||||
cls: `toast toast--${options.type}`,
|
||||
cls: `sn-toast sn-toast--${options.type}`,
|
||||
attr: {
|
||||
role: 'alert',
|
||||
'aria-live': options.type === 'error' ? 'assertive' : 'polite',
|
||||
|
|
@ -105,28 +105,28 @@ export class ToastNotification {
|
|||
|
||||
// 아이콘
|
||||
if (options.icon !== false) {
|
||||
const iconContainer = createEl('div', { cls: 'toast__icon' });
|
||||
const iconContainer = createEl('div', { cls: 'sn-toast__icon' });
|
||||
const statusIcon = new StatusIcon(options.type, undefined);
|
||||
iconContainer.appendChild(statusIcon.create());
|
||||
toast.appendChild(iconContainer);
|
||||
}
|
||||
|
||||
// 콘텐츠
|
||||
const content = createEl('div', { cls: 'toast__content' });
|
||||
const content = createEl('div', { cls: 'sn-toast__content' });
|
||||
|
||||
if (options.title) {
|
||||
const title = createEl('div', { cls: 'toast__title', text: options.title });
|
||||
const title = createEl('div', { cls: 'sn-toast__title', text: options.title });
|
||||
content.appendChild(title);
|
||||
}
|
||||
|
||||
const message = createEl('div', { cls: 'toast__message', text: options.message });
|
||||
const message = createEl('div', { cls: 'sn-toast__message', text: options.message });
|
||||
content.appendChild(message);
|
||||
|
||||
// 진행률 바
|
||||
if (options.progress !== undefined) {
|
||||
const progressBar = createEl('div', { cls: 'toast__progress' });
|
||||
const progressBar = createEl('div', { cls: 'sn-toast__progress' });
|
||||
const progressFill = createEl('div', {
|
||||
cls: 'toast__progress-fill',
|
||||
cls: 'sn-toast__progress-fill',
|
||||
attr: { style: `--sn-progress-width:${options.progress}%` },
|
||||
});
|
||||
progressBar.appendChild(progressFill);
|
||||
|
|
@ -135,11 +135,11 @@ export class ToastNotification {
|
|||
|
||||
// 액션 버튼
|
||||
if (options.actions && options.actions.length > 0) {
|
||||
const actions = createEl('div', { cls: 'toast__actions' });
|
||||
const actions = createEl('div', { cls: 'sn-toast__actions' });
|
||||
|
||||
options.actions.forEach((action) => {
|
||||
const button = createEl('button', {
|
||||
cls: `toast__action toast__action--${action.style || 'link'}`,
|
||||
cls: `sn-toast__action sn-toast__action--${action.style || 'link'}`,
|
||||
text: action.label,
|
||||
});
|
||||
button.addEventListener('click', () => {
|
||||
|
|
@ -157,7 +157,7 @@ export class ToastNotification {
|
|||
// 닫기 버튼
|
||||
if (options.closable !== false) {
|
||||
const closeBtn = createEl('button', {
|
||||
cls: 'toast__close',
|
||||
cls: 'sn-toast__close',
|
||||
text: '×',
|
||||
attr: { 'aria-label': 'Dismiss notification' },
|
||||
});
|
||||
|
|
@ -171,7 +171,7 @@ export class ToastNotification {
|
|||
|
||||
// 애니메이션
|
||||
requestAnimationFrame(() => {
|
||||
toast.classList.add('toast--show');
|
||||
toast.classList.add('sn-toast--show');
|
||||
});
|
||||
|
||||
// 사운드 재생
|
||||
|
|
@ -200,8 +200,8 @@ export class ToastNotification {
|
|||
const toast = this.notifications.get(id);
|
||||
if (!toast) return;
|
||||
|
||||
toast.classList.remove('toast--show');
|
||||
toast.classList.add('toast--hide');
|
||||
toast.classList.remove('sn-toast--show');
|
||||
toast.classList.add('sn-toast--hide');
|
||||
|
||||
setTimeout(() => {
|
||||
toast.remove();
|
||||
|
|
@ -232,7 +232,7 @@ export class ToastNotification {
|
|||
const toast = this.notifications.get(id);
|
||||
if (!toast) return;
|
||||
|
||||
const progressFill = toast.querySelector('.toast__progress-fill');
|
||||
const progressFill = toast.querySelector('.sn-toast__progress-fill');
|
||||
if (progressFill instanceof HTMLElement) {
|
||||
progressFill.setAttribute('style', `--sn-progress-width:${progress}%`);
|
||||
}
|
||||
|
|
@ -354,7 +354,7 @@ export class ModalNotification {
|
|||
}
|
||||
|
||||
// 오버레이 생성
|
||||
this.overlay = createEl('div', { cls: 'modal-overlay' });
|
||||
this.overlay = createEl('div', { cls: 'sn-modal-overlay' });
|
||||
this.overlay.addEventListener('click', () => {
|
||||
if (options.closable !== false) {
|
||||
this.dismiss();
|
||||
|
|
@ -364,7 +364,7 @@ export class ModalNotification {
|
|||
|
||||
// 모달 생성
|
||||
this.activeModal = createEl('div', {
|
||||
cls: `modal-notification modal-notification--${options.type}`,
|
||||
cls: `sn-modal-notification sn-modal-notification--${options.type}`,
|
||||
attr: {
|
||||
role: 'alertdialog',
|
||||
'aria-modal': 'true',
|
||||
|
|
@ -374,7 +374,7 @@ export class ModalNotification {
|
|||
});
|
||||
|
||||
// 헤더
|
||||
const header = createEl('div', { cls: 'modal-notification__header' });
|
||||
const header = createEl('div', { cls: 'sn-modal-notification__header' });
|
||||
|
||||
if (options.icon !== false) {
|
||||
const statusIcon = new StatusIcon(options.type, undefined);
|
||||
|
|
@ -383,7 +383,7 @@ export class ModalNotification {
|
|||
|
||||
if (options.title) {
|
||||
const title = createEl('h2', {
|
||||
cls: 'modal-notification__title',
|
||||
cls: 'sn-modal-notification__title',
|
||||
text: options.title,
|
||||
attr: { id: 'modal-title' },
|
||||
});
|
||||
|
|
@ -392,7 +392,7 @@ export class ModalNotification {
|
|||
|
||||
if (options.closable !== false) {
|
||||
const closeBtn = createEl('button', {
|
||||
cls: 'modal-notification__close',
|
||||
cls: 'sn-modal-notification__close',
|
||||
text: '×',
|
||||
attr: { 'aria-label': 'Close' },
|
||||
});
|
||||
|
|
@ -407,7 +407,7 @@ export class ModalNotification {
|
|||
|
||||
// 본문
|
||||
const body = createEl('div', {
|
||||
cls: 'modal-notification__body',
|
||||
cls: 'sn-modal-notification__body',
|
||||
text: options.message,
|
||||
attr: { id: 'modal-message' },
|
||||
});
|
||||
|
|
@ -415,11 +415,11 @@ export class ModalNotification {
|
|||
|
||||
// 액션 버튼
|
||||
if (options.actions && options.actions.length > 0) {
|
||||
const footer = createEl('div', { cls: 'modal-notification__footer' });
|
||||
const footer = createEl('div', { cls: 'sn-modal-notification__footer' });
|
||||
|
||||
options.actions.forEach((action) => {
|
||||
const button = createEl('button', {
|
||||
cls: `modal-notification__action modal-notification__action--${
|
||||
cls: `sn-modal-notification__action sn-modal-notification__action--${
|
||||
action.style || 'secondary'
|
||||
}`,
|
||||
text: action.label,
|
||||
|
|
@ -447,8 +447,8 @@ export class ModalNotification {
|
|||
|
||||
// 애니메이션
|
||||
requestAnimationFrame(() => {
|
||||
this.overlay?.classList.add('modal-overlay--show');
|
||||
this.activeModal?.classList.add('modal-notification--show');
|
||||
this.overlay?.classList.add('sn-modal-overlay--show');
|
||||
this.activeModal?.classList.add('sn-modal-notification--show');
|
||||
});
|
||||
|
||||
// 사운드 재생
|
||||
|
|
@ -474,8 +474,8 @@ export class ModalNotification {
|
|||
static dismiss() {
|
||||
if (!this.activeModal || !this.overlay) return;
|
||||
|
||||
this.activeModal.classList.remove('modal-notification--show');
|
||||
this.overlay.classList.remove('modal-overlay--show');
|
||||
this.activeModal.classList.remove('sn-modal-notification--show');
|
||||
this.overlay.classList.remove('sn-modal-overlay--show');
|
||||
|
||||
setTimeout(() => {
|
||||
this.activeModal?.remove();
|
||||
|
|
@ -500,7 +500,7 @@ export class StatusBarNotification {
|
|||
private static initContainer() {
|
||||
if (!this.container) {
|
||||
this.container = createEl('div', {
|
||||
cls: 'statusbar-notification',
|
||||
cls: 'sn-statusbar-notification',
|
||||
attr: {
|
||||
role: 'status',
|
||||
'aria-live': 'polite',
|
||||
|
|
@ -528,12 +528,12 @@ export class StatusBarNotification {
|
|||
|
||||
// 알림 생성
|
||||
this.currentNotification = createEl('div', {
|
||||
cls: `statusbar-notification__content statusbar-notification__content--${options.type}`,
|
||||
cls: `sn-statusbar-notification__content sn-statusbar-notification__content--${options.type}`,
|
||||
});
|
||||
|
||||
// 아이콘
|
||||
if (options.icon !== false) {
|
||||
const iconContainer = createEl('span', { cls: 'statusbar-notification__icon' });
|
||||
const iconContainer = createEl('span', { cls: 'sn-statusbar-notification__icon' });
|
||||
const statusIcon = new StatusIcon(options.type, undefined);
|
||||
iconContainer.appendChild(statusIcon.create());
|
||||
this.currentNotification.appendChild(iconContainer);
|
||||
|
|
@ -541,7 +541,7 @@ export class StatusBarNotification {
|
|||
|
||||
// 메시지
|
||||
const message = createEl('span', {
|
||||
cls: 'statusbar-notification__message',
|
||||
cls: 'sn-statusbar-notification__message',
|
||||
text: options.message,
|
||||
});
|
||||
this.currentNotification.appendChild(message);
|
||||
|
|
@ -550,7 +550,7 @@ export class StatusBarNotification {
|
|||
if (options.actions && options.actions.length > 0) {
|
||||
const action = options.actions[0]; // 상태바는 하나의 액션만 지원
|
||||
const button = createEl('button', {
|
||||
cls: 'statusbar-notification__action',
|
||||
cls: 'sn-statusbar-notification__action',
|
||||
text: action.label,
|
||||
});
|
||||
button.addEventListener('click', () => {
|
||||
|
|
@ -563,7 +563,7 @@ export class StatusBarNotification {
|
|||
// 닫기 버튼
|
||||
if (options.closable !== false) {
|
||||
const closeBtn = createEl('button', {
|
||||
cls: 'statusbar-notification__close',
|
||||
cls: 'sn-statusbar-notification__close',
|
||||
text: '×',
|
||||
attr: { 'aria-label': 'Close' },
|
||||
});
|
||||
|
|
@ -576,7 +576,7 @@ export class StatusBarNotification {
|
|||
|
||||
// 애니메이션
|
||||
requestAnimationFrame(() => {
|
||||
this.container?.classList.add('statusbar-notification--show');
|
||||
this.container?.classList.add('sn-statusbar-notification--show');
|
||||
});
|
||||
|
||||
// 자동 숨기기
|
||||
|
|
@ -592,7 +592,7 @@ export class StatusBarNotification {
|
|||
static hide() {
|
||||
if (!this.container) return;
|
||||
|
||||
this.container.classList.remove('statusbar-notification--show');
|
||||
this.container.classList.remove('sn-statusbar-notification--show');
|
||||
|
||||
setTimeout(() => {
|
||||
this.currentNotification?.remove();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export class CircularProgress {
|
|||
}
|
||||
|
||||
create(container: HTMLElement): HTMLElement {
|
||||
this.element = createEl('div', { cls: 'circular-progress' });
|
||||
this.element = createEl('div', { cls: 'sn-circular-progress' });
|
||||
this.element.style.setProperty('--cp-size', `${this.options.size}px`);
|
||||
this.element.style.setProperty(
|
||||
'--cp-animation-duration',
|
||||
|
|
@ -96,7 +96,7 @@ export class CircularProgress {
|
|||
this.progressCircle.setAttribute('stroke-dashoffset', String(offset));
|
||||
|
||||
// 애니메이션 설정
|
||||
this.progressCircle.classList.add('circular-progress__circle');
|
||||
this.progressCircle.classList.add('sn-circular-progress__circle');
|
||||
|
||||
this.svg.appendChild(this.backgroundCircle);
|
||||
this.svg.appendChild(this.progressCircle);
|
||||
|
|
@ -263,7 +263,7 @@ export class CircularProgress {
|
|||
*/
|
||||
export class SemiCircularProgress extends CircularProgress {
|
||||
create(container: HTMLElement): HTMLElement {
|
||||
this.element = createEl('div', { cls: 'semi-circular-progress' });
|
||||
this.element = createEl('div', { cls: 'sn-semi-circular-progress' });
|
||||
this.element.style.setProperty('--cp-size', `${this.options.size}px`);
|
||||
this.element.style.setProperty(
|
||||
'--cp-animation-duration',
|
||||
|
|
@ -296,7 +296,7 @@ export class SemiCircularProgress extends CircularProgress {
|
|||
this.progressCircle.setAttribute('stroke-width', String(this.options.strokeWidth));
|
||||
this.progressCircle.setAttribute('stroke-linecap', 'round');
|
||||
this.progressCircle.setAttribute('stroke-dasharray', String(circumference));
|
||||
this.progressCircle.classList.add('semi-circular-progress__circle');
|
||||
this.progressCircle.classList.add('sn-semi-circular-progress__circle');
|
||||
|
||||
// 초기 진행률 설정
|
||||
const offset = circumference - (this.currentProgress / 100) * circumference;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export class ProgressBar {
|
|||
|
||||
create(container: HTMLElement): HTMLElement {
|
||||
this.element = createEl('div', {
|
||||
cls: `progress-bar progress-bar--${this.options.size} progress-bar--${this.options.color}`,
|
||||
cls: `sn-progress-bar sn-progress-bar--${this.options.size} sn-progress-bar--${this.options.color}`,
|
||||
});
|
||||
this.element.setAttribute('role', 'progressbar');
|
||||
this.element.setAttribute('aria-valuemin', String(this.options.min));
|
||||
|
|
@ -79,24 +79,24 @@ export class ProgressBar {
|
|||
// 라벨
|
||||
if (this.options.label) {
|
||||
this.labelElement = createEl('div', {
|
||||
cls: 'progress-bar__label',
|
||||
cls: 'sn-progress-bar__label',
|
||||
text: this.options.label,
|
||||
});
|
||||
this.element.appendChild(this.labelElement);
|
||||
}
|
||||
|
||||
// 진행률 바 컨테이너
|
||||
const barContainer = createEl('div', { cls: 'progress-bar__container' });
|
||||
const barContainer = createEl('div', { cls: 'sn-progress-bar__container' });
|
||||
|
||||
// 진행률 채우기
|
||||
this.progressFill = createEl('div', { cls: 'progress-bar__fill' });
|
||||
this.progressFill = createEl('div', { cls: 'sn-progress-bar__fill' });
|
||||
|
||||
if (this.options.striped) {
|
||||
this.progressFill.classList.add('progress-bar__fill--striped');
|
||||
this.progressFill.classList.add('sn-progress-bar__fill--striped');
|
||||
}
|
||||
|
||||
if (this.options.indeterminate) {
|
||||
this.progressFill.classList.add('progress-bar__fill--indeterminate');
|
||||
this.progressFill.classList.add('sn-progress-bar__fill--indeterminate');
|
||||
} else {
|
||||
this.updateProgress(this.currentValue);
|
||||
}
|
||||
|
|
@ -105,12 +105,12 @@ export class ProgressBar {
|
|||
this.element.appendChild(barContainer);
|
||||
|
||||
// 정보 표시 영역
|
||||
const infoContainer = createEl('div', { cls: 'progress-bar__info' });
|
||||
const infoContainer = createEl('div', { cls: 'sn-progress-bar__info' });
|
||||
|
||||
// 퍼센트 표시
|
||||
if (this.options.showPercentage && !this.options.indeterminate) {
|
||||
this.percentageElement = createEl('span', {
|
||||
cls: 'progress-bar__percentage',
|
||||
cls: 'sn-progress-bar__percentage',
|
||||
text: '0%',
|
||||
});
|
||||
infoContainer.appendChild(this.percentageElement);
|
||||
|
|
@ -119,7 +119,7 @@ export class ProgressBar {
|
|||
// 예상 시간 표시
|
||||
if (this.options.showTimeRemaining && !this.options.indeterminate) {
|
||||
this.timeRemainingElement = createEl('span', {
|
||||
cls: 'progress-bar__time-remaining',
|
||||
cls: 'sn-progress-bar__time-remaining',
|
||||
text: 'Calculating...',
|
||||
});
|
||||
infoContainer.appendChild(this.timeRemainingElement);
|
||||
|
|
@ -292,14 +292,14 @@ export class ProgressBar {
|
|||
|
||||
// 기존 색상 클래스 제거
|
||||
this.element.classList.remove(
|
||||
'progress-bar--primary',
|
||||
'progress-bar--success',
|
||||
'progress-bar--warning',
|
||||
'progress-bar--error'
|
||||
'sn-progress-bar--primary',
|
||||
'sn-progress-bar--success',
|
||||
'sn-progress-bar--warning',
|
||||
'sn-progress-bar--error'
|
||||
);
|
||||
|
||||
// 새 색상 클래스 추가
|
||||
this.element.classList.add(`progress-bar--${color}`);
|
||||
this.element.classList.add(`sn-progress-bar--${color}`);
|
||||
this.options.color = color;
|
||||
}
|
||||
|
||||
|
|
@ -308,7 +308,7 @@ export class ProgressBar {
|
|||
*/
|
||||
setLabel(label: string) {
|
||||
if (!this.labelElement) {
|
||||
this.labelElement = createEl('div', { cls: 'progress-bar__label' });
|
||||
this.labelElement = createEl('div', { cls: 'sn-progress-bar__label' });
|
||||
this.element?.insertBefore(this.labelElement, this.element.firstChild);
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ export class ProgressBar {
|
|||
if (!this.progressFill) return;
|
||||
|
||||
if (indeterminate) {
|
||||
this.progressFill.classList.add('progress-bar__fill--indeterminate');
|
||||
this.progressFill.classList.add('sn-progress-bar__fill--indeterminate');
|
||||
this.progressFill.removeAttribute('style');
|
||||
|
||||
if (this.percentageElement) {
|
||||
|
|
@ -335,7 +335,7 @@ export class ProgressBar {
|
|||
this.timeRemainingElement.classList.add('sn-hidden');
|
||||
}
|
||||
} else {
|
||||
this.progressFill.classList.remove('progress-bar__fill--indeterminate');
|
||||
this.progressFill.classList.remove('sn-progress-bar__fill--indeterminate');
|
||||
this.updateProgress(this.currentValue);
|
||||
|
||||
if (this.percentageElement) {
|
||||
|
|
@ -387,10 +387,10 @@ export class MultiStepProgressBar {
|
|||
}
|
||||
|
||||
create(container: HTMLElement): HTMLElement {
|
||||
this.element = createEl('div', { cls: 'multi-step-progress' });
|
||||
this.element = createEl('div', { cls: 'sn-multi-step-progress' });
|
||||
|
||||
// 단계 표시
|
||||
this.stepsContainer = createEl('div', { cls: 'multi-step-progress__steps' });
|
||||
this.stepsContainer = createEl('div', { cls: 'sn-multi-step-progress__steps' });
|
||||
const stepsContainer = this.stepsContainer;
|
||||
if (!stepsContainer) {
|
||||
container.appendChild(this.element);
|
||||
|
|
@ -402,12 +402,12 @@ export class MultiStepProgressBar {
|
|||
stepEl.setAttribute('data-step-id', step.id);
|
||||
|
||||
const stepNumber = createEl('span', {
|
||||
cls: 'step__number',
|
||||
cls: 'sn-step__number',
|
||||
text: String(index + 1),
|
||||
});
|
||||
|
||||
const stepLabel = createEl('span', {
|
||||
cls: 'step__label',
|
||||
cls: 'sn-step__label',
|
||||
text: step.label,
|
||||
});
|
||||
|
||||
|
|
@ -426,7 +426,7 @@ export class MultiStepProgressBar {
|
|||
this.element.appendChild(stepsContainer);
|
||||
|
||||
// 전체 진행률 바
|
||||
const progressContainer = createEl('div', { cls: 'multi-step-progress__bar' });
|
||||
const progressContainer = createEl('div', { cls: 'sn-multi-step-progress__bar' });
|
||||
this.progressBar.create(progressContainer);
|
||||
this.element.appendChild(progressContainer);
|
||||
|
||||
|
|
@ -499,7 +499,7 @@ export class MultiStepProgressBar {
|
|||
|
||||
const stepEl = this.stepsContainer?.querySelector(`[data-step-id="${stepId}"]`);
|
||||
if (stepEl) {
|
||||
stepEl.className = `step step--${status}`;
|
||||
stepEl.className = `sn-step sn-step--${status}`;
|
||||
|
||||
// ARIA 속성 업데이트
|
||||
switch (status) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export class UIComponentFactory {
|
|||
});
|
||||
|
||||
if (icon) {
|
||||
statusEl.createSpan({ text: icon, cls: 'status-icon' });
|
||||
statusEl.createSpan({ text: icon, cls: 'sn-status-icon' });
|
||||
}
|
||||
|
||||
statusEl.createSpan({ text, cls: 'status-text' });
|
||||
|
|
@ -53,7 +53,7 @@ export class UIComponentFactory {
|
|||
}
|
||||
|
||||
const progressBar = progressContainer.createDiv({
|
||||
cls: 'progress-bar',
|
||||
cls: 'sn-progress-bar',
|
||||
attr: {
|
||||
role: 'progressbar',
|
||||
'aria-valuenow': String(value),
|
||||
|
|
@ -64,7 +64,7 @@ export class UIComponentFactory {
|
|||
});
|
||||
|
||||
const progressFill = progressBar.createDiv({
|
||||
cls: 'progress-fill',
|
||||
cls: 'sn-progress-fill',
|
||||
attr: {
|
||||
style: `width: ${(value / max) * 100}%`,
|
||||
},
|
||||
|
|
@ -73,7 +73,7 @@ export class UIComponentFactory {
|
|||
// 접근성을 위한 텍스트
|
||||
progressFill.createSpan({
|
||||
text: `${Math.round((value / max) * 100)}%`,
|
||||
cls: 'progress-text',
|
||||
cls: 'sn-progress-text',
|
||||
});
|
||||
|
||||
return progressContainer;
|
||||
|
|
@ -198,7 +198,7 @@ export class UIComponentFactory {
|
|||
// 탭 버튼
|
||||
const tabButton = tabList.createEl('button', {
|
||||
text: tab.label,
|
||||
cls: `tab-button ${tab.id === activeTab ? 'active' : ''}`,
|
||||
cls: `sn-tab-button ${tab.id === activeTab ? 'sn-is-active' : ''}`,
|
||||
attr: {
|
||||
role: 'tab',
|
||||
id: `tab-${tab.id}`,
|
||||
|
|
@ -210,7 +210,7 @@ export class UIComponentFactory {
|
|||
|
||||
// 탭 패널
|
||||
const tabPanel = tabPanels.createDiv({
|
||||
cls: `tab-panel ${tab.id === activeTab ? 'active' : ''}`,
|
||||
cls: `sn-tab-panel ${tab.id === activeTab ? 'sn-is-active' : ''}`,
|
||||
attr: {
|
||||
role: 'tabpanel',
|
||||
id: `panel-${tab.id}`,
|
||||
|
|
@ -226,14 +226,14 @@ export class UIComponentFactory {
|
|||
// 이벤트 핸들러
|
||||
tabButton.onclick = () => {
|
||||
// 모든 탭 비활성화
|
||||
tabList.querySelectorAll('.tab-button').forEach((btn) => {
|
||||
btn.classList.remove('active');
|
||||
tabList.querySelectorAll('.sn-tab-button').forEach((btn) => {
|
||||
btn.classList.remove('sn-is-active');
|
||||
btn.setAttribute('aria-selected', 'false');
|
||||
btn.setAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
tabPanels.querySelectorAll('.tab-panel').forEach((panel) => {
|
||||
panel.classList.remove('active');
|
||||
tabPanels.querySelectorAll('.sn-tab-panel').forEach((panel) => {
|
||||
panel.classList.remove('sn-is-active');
|
||||
panel.setAttribute('hidden', 'true');
|
||||
if (panel instanceof HTMLElement) {
|
||||
panel.empty();
|
||||
|
|
@ -241,11 +241,11 @@ export class UIComponentFactory {
|
|||
});
|
||||
|
||||
// 선택된 탭 활성화
|
||||
tabButton.classList.add('active');
|
||||
tabButton.classList.add('sn-is-active');
|
||||
tabButton.setAttribute('aria-selected', 'true');
|
||||
tabButton.setAttribute('tabindex', '0');
|
||||
|
||||
tabPanel.classList.add('active');
|
||||
tabPanel.classList.add('sn-is-active');
|
||||
tabPanel.removeAttribute('hidden');
|
||||
tabPanel.appendChild(tab.content());
|
||||
|
||||
|
|
@ -269,7 +269,7 @@ export class UIComponentFactory {
|
|||
}
|
||||
|
||||
e.preventDefault();
|
||||
const newTab = tabList.querySelectorAll('.tab-button')[newIndex];
|
||||
const newTab = tabList.querySelectorAll('.sn-tab-button')[newIndex];
|
||||
if (newTab instanceof HTMLElement) {
|
||||
newTab.click();
|
||||
newTab.focus();
|
||||
|
|
@ -294,7 +294,7 @@ export class UIComponentFactory {
|
|||
*/
|
||||
static createLoadingSpinner(containerEl: HTMLElement, text = 'Loading...'): HTMLElement {
|
||||
const spinnerEl = containerEl.createDiv({
|
||||
cls: 'loading-spinner',
|
||||
cls: 'sn-loading-spinner',
|
||||
attr: {
|
||||
role: 'status',
|
||||
'aria-label': text,
|
||||
|
|
@ -302,7 +302,7 @@ export class UIComponentFactory {
|
|||
});
|
||||
|
||||
spinnerEl.createDiv({ cls: 'spinner' });
|
||||
spinnerEl.createSpan({ text, cls: 'spinner-text' });
|
||||
spinnerEl.createSpan({ text, cls: 'sn-loading-message' });
|
||||
|
||||
return spinnerEl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,32 @@
|
|||
/* File Picker Modal Styles */
|
||||
.file-picker-modal {
|
||||
.sn-file-picker-modal {
|
||||
max-width: 800px;
|
||||
max-height: 600px;
|
||||
}
|
||||
|
||||
.file-picker-modal .modal-content {
|
||||
.sn-file-picker-modal .modal-content {
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.file-picker-header {
|
||||
.sn-file-picker-header {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.file-picker-header h2 {
|
||||
.sn-file-picker-header h2 {
|
||||
margin: 0 0 10px 0;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.file-picker-subtitle {
|
||||
.sn-file-picker-subtitle {
|
||||
color: var(--text-muted);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Drag & Drop Zone */
|
||||
.drag-drop-zone {
|
||||
.sn-drag-drop-zone {
|
||||
border: 2px dashed var(--background-modifier-border);
|
||||
border-radius: 8px;
|
||||
padding: 40px 20px;
|
||||
|
|
@ -37,48 +37,48 @@
|
|||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
.drag-drop-zone:hover {
|
||||
.sn-drag-drop-zone:hover {
|
||||
border-color: var(--interactive-accent);
|
||||
background: var(--background-primary-alt);
|
||||
}
|
||||
|
||||
.drag-drop-zone.dragging {
|
||||
.sn-drag-drop-zone.sn-is-dragging {
|
||||
border-color: var(--interactive-accent);
|
||||
background: var(--background-primary-alt);
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.drop-zone-icon {
|
||||
.sn-drop-zone-icon {
|
||||
margin-bottom: 20px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.drop-zone-icon svg {
|
||||
.sn-drop-zone-icon svg {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.drop-zone-text h3 {
|
||||
.sn-drop-zone-text h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.drop-zone-subtext {
|
||||
.sn-drop-zone-subtext {
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.drop-zone-formats {
|
||||
.sn-drop-zone-formats {
|
||||
font-size: 12px;
|
||||
color: var(--text-faint);
|
||||
}
|
||||
|
||||
.drop-zone-input {
|
||||
.sn-drop-zone-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Drag Overlay */
|
||||
.drag-overlay {
|
||||
.sn-drag-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
@ -93,22 +93,22 @@
|
|||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.drag-overlay.active {
|
||||
.sn-drag-overlay.sn-is-active {
|
||||
display: flex;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.drag-overlay-content {
|
||||
.sn-drag-overlay-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.drag-overlay-icon svg {
|
||||
.sn-drag-overlay-icon svg {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.drag-overlay-text {
|
||||
.sn-drag-overlay-text {
|
||||
margin-top: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
|
|
@ -116,7 +116,7 @@
|
|||
}
|
||||
|
||||
/* Drop Zone Messages */
|
||||
.drop-zone-message {
|
||||
.sn-drop-zone-message {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
|
|
@ -124,31 +124,31 @@
|
|||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
animation: slideUp 0.3s ease;
|
||||
animation: sn-file-picker-slide-up 0.3s ease;
|
||||
}
|
||||
|
||||
.drop-zone-message.success {
|
||||
.sn-drop-zone-message.sn-drop-zone-message--success {
|
||||
background: var(--background-modifier-success);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
.drop-zone-message.error {
|
||||
.sn-drop-zone-message.sn-drop-zone-message--error {
|
||||
background: var(--background-modifier-error);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.file-picker-tabs {
|
||||
.sn-file-picker-tabs {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
.sn-tab-header {
|
||||
display: flex;
|
||||
border-bottom: 2px solid var(--background-modifier-border);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
.sn-tab-button {
|
||||
padding: 10px 20px;
|
||||
background: none;
|
||||
border: none;
|
||||
|
|
@ -160,15 +160,15 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.tab-button:hover {
|
||||
.sn-tab-button:hover {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.tab-button.active {
|
||||
.sn-tab-button.sn-is-active {
|
||||
color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.tab-button.active::after {
|
||||
.sn-tab-button.sn-is-active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
|
|
@ -178,27 +178,27 @@
|
|||
background: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
.sn-tab-content {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.browse-content,
|
||||
.recent-content {
|
||||
.sn-browse-content,
|
||||
.sn-recent-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.browse-content.active,
|
||||
.recent-content.active {
|
||||
.sn-browse-content.sn-is-active,
|
||||
.sn-recent-content.sn-is-active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* File Browser */
|
||||
.file-browser {
|
||||
.sn-file-browser {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.file-browser-toolbar {
|
||||
.sn-file-browser-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
|
@ -208,12 +208,12 @@
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
.sn-search-container {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
.sn-search-input {
|
||||
width: 100%;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
|
|
@ -222,13 +222,13 @@
|
|||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.sort-container {
|
||||
.sn-sort-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.sort-select {
|
||||
.sn-sort-select {
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
|
|
@ -236,8 +236,8 @@
|
|||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.sort-order-btn,
|
||||
.refresh-btn {
|
||||
.sn-sort-order-btn,
|
||||
.sn-refresh-btn {
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
|
|
@ -246,18 +246,18 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sort-order-btn:hover,
|
||||
.refresh-btn:hover {
|
||||
.sn-sort-order-btn:hover,
|
||||
.sn-refresh-btn:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
/* File List */
|
||||
.file-browser-list {
|
||||
.sn-file-browser-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.folder-header {
|
||||
.sn-folder-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
|
|
@ -268,35 +268,35 @@
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
.folder-header:hover {
|
||||
.sn-folder-header:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.folder-header.collapsed .folder-icon {
|
||||
.sn-folder-header.sn-is-collapsed .sn-folder-icon {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.folder-icon {
|
||||
.sn-folder-icon {
|
||||
margin-right: 8px;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.folder-name {
|
||||
.sn-folder-name {
|
||||
flex: 1;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.folder-count {
|
||||
.sn-folder-count {
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.folder-files {
|
||||
.sn-folder-files {
|
||||
margin-left: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
.sn-file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
|
|
@ -305,29 +305,29 @@
|
|||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
.sn-file-item:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.file-item.selected {
|
||||
.sn-file-item.sn-is-selected {
|
||||
background: var(--background-modifier-active-hover);
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
.sn-file-icon {
|
||||
margin-right: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.file-info {
|
||||
.sn-file-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
.sn-file-name {
|
||||
color: var(--text-normal);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.file-meta {
|
||||
.sn-file-meta {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
font-size: 12px;
|
||||
|
|
@ -335,24 +335,24 @@
|
|||
}
|
||||
|
||||
/* Recent Files */
|
||||
.recent-files {
|
||||
.sn-recent-files {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.recent-files-header {
|
||||
.sn-recent-files-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.recent-files-header h3 {
|
||||
.sn-recent-files-header h3 {
|
||||
margin: 0;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.clear-recent-btn {
|
||||
.sn-clear-recent-btn {
|
||||
padding: 4px 10px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
|
|
@ -362,17 +362,17 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clear-recent-btn:hover {
|
||||
.sn-clear-recent-btn:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.recent-files-list {
|
||||
.sn-recent-files-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.recent-file-item {
|
||||
.sn-recent-file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
|
|
@ -382,15 +382,15 @@
|
|||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.recent-file-item:hover {
|
||||
.sn-recent-file-item:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.recent-file-item.file-not-found {
|
||||
.sn-recent-file-item.sn-is-file-not-found {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.file-order {
|
||||
.sn-file-order {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
|
|
@ -404,13 +404,13 @@
|
|||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.file-actions {
|
||||
.sn-file-actions {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.select-btn,
|
||||
.remove-btn {
|
||||
.sn-select-btn,
|
||||
.sn-remove-btn {
|
||||
padding: 4px 8px;
|
||||
border: none;
|
||||
background: none;
|
||||
|
|
@ -419,32 +419,32 @@
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.select-btn:hover,
|
||||
.remove-btn:hover {
|
||||
.sn-select-btn:hover,
|
||||
.sn-remove-btn:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
/* Selected Files Section */
|
||||
.selected-files-section {
|
||||
.sn-selected-files-section {
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
background: var(--background-secondary);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.selected-files-section h3 {
|
||||
.sn-selected-files-section h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: var(--text-normal);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.selected-files-list {
|
||||
.sn-selected-files-list {
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.selected-file-item {
|
||||
.sn-selected-file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 10px;
|
||||
|
|
@ -453,14 +453,14 @@
|
|||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.selected-file-item .file-info {
|
||||
.sn-selected-file-item .sn-file-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.validation-status {
|
||||
.sn-validation-status {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
|
|
@ -471,17 +471,17 @@
|
|||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.validation-status.valid {
|
||||
.sn-validation-status.sn-is-valid {
|
||||
background: var(--background-modifier-success);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
.validation-status.invalid {
|
||||
.sn-validation-status.sn-is-invalid {
|
||||
background: var(--background-modifier-error);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
.remove-file-btn {
|
||||
.sn-remove-file-btn {
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
|
|
@ -491,12 +491,12 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.remove-file-btn:hover {
|
||||
.sn-remove-file-btn:hover {
|
||||
background: var(--background-modifier-error);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
.no-files-message {
|
||||
.sn-no-files-message {
|
||||
color: var(--text-muted);
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
|
|
@ -504,7 +504,7 @@
|
|||
}
|
||||
|
||||
/* Progress Indicator */
|
||||
.progress-indicator {
|
||||
.sn-progress-indicator {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
@ -515,11 +515,11 @@
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
.progress-indicator.sn-flex {
|
||||
.sn-progress-indicator.sn-flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.progress-overlay {
|
||||
.sn-progress-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
@ -528,7 +528,7 @@
|
|||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.progress-content {
|
||||
.sn-progress-content {
|
||||
position: relative;
|
||||
background: var(--background-primary);
|
||||
border-radius: 8px;
|
||||
|
|
@ -538,24 +538,24 @@
|
|||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.progress-content.error {
|
||||
.sn-progress-content.sn-is-error {
|
||||
border: 2px solid var(--background-modifier-error);
|
||||
}
|
||||
|
||||
.progress-content.success {
|
||||
.sn-progress-content.sn-is-success {
|
||||
border: 2px solid var(--background-modifier-success);
|
||||
}
|
||||
|
||||
.progress-spinner {
|
||||
.sn-progress-spinner {
|
||||
margin-bottom: 20px;
|
||||
color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.progress-spinner.is-spinning svg {
|
||||
animation: spin 1s linear infinite;
|
||||
.sn-progress-spinner.sn-is-spinning svg {
|
||||
animation: sn-file-picker-spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
@keyframes sn-file-picker-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
|
@ -564,11 +564,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.progress-bar-container {
|
||||
.sn-progress-bar-container {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
.sn-progress-bar {
|
||||
height: 20px;
|
||||
background: var(--background-modifier-border);
|
||||
border-radius: 10px;
|
||||
|
|
@ -576,21 +576,21 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
.sn-progress-fill {
|
||||
height: 100%;
|
||||
background: var(--interactive-accent);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.progress-fill.progress-warning {
|
||||
.sn-progress-fill.sn-is-warning {
|
||||
background: var(--text-warning);
|
||||
}
|
||||
|
||||
.progress-fill.progress-success {
|
||||
.sn-progress-fill.sn-is-success {
|
||||
background: var(--text-success);
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
.sn-progress-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
|
@ -600,12 +600,12 @@
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
.progress-message {
|
||||
.sn-progress-message {
|
||||
color: var(--text-normal);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.progress-cancel-btn {
|
||||
.sn-progress-cancel-btn {
|
||||
padding: 8px 20px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
|
|
@ -614,12 +614,12 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.progress-cancel-btn:hover {
|
||||
.sn-progress-cancel-btn:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
/* Empty State */
|
||||
.empty-state {
|
||||
.sn-empty-state {
|
||||
padding: 40px 20px;
|
||||
text-align: center;
|
||||
color: var(--text-muted);
|
||||
|
|
@ -627,14 +627,14 @@
|
|||
}
|
||||
|
||||
/* Footer */
|
||||
.file-picker-footer {
|
||||
.sn-file-picker-footer {
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes slideUp {
|
||||
@keyframes sn-file-picker-slide-up {
|
||||
from {
|
||||
transform: translateX(-50%) translateY(10px);
|
||||
opacity: 0;
|
||||
|
|
@ -646,27 +646,27 @@
|
|||
}
|
||||
|
||||
/* Scrollbar Styles */
|
||||
.file-browser-list::-webkit-scrollbar,
|
||||
.selected-files-list::-webkit-scrollbar,
|
||||
.recent-files-list::-webkit-scrollbar {
|
||||
.sn-file-browser-list::-webkit-scrollbar,
|
||||
.sn-selected-files-list::-webkit-scrollbar,
|
||||
.sn-recent-files-list::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.file-browser-list::-webkit-scrollbar-track,
|
||||
.selected-files-list::-webkit-scrollbar-track,
|
||||
.recent-files-list::-webkit-scrollbar-track {
|
||||
.sn-file-browser-list::-webkit-scrollbar-track,
|
||||
.sn-selected-files-list::-webkit-scrollbar-track,
|
||||
.sn-recent-files-list::-webkit-scrollbar-track {
|
||||
background: var(--background-secondary);
|
||||
}
|
||||
|
||||
.file-browser-list::-webkit-scrollbar-thumb,
|
||||
.selected-files-list::-webkit-scrollbar-thumb,
|
||||
.recent-files-list::-webkit-scrollbar-thumb {
|
||||
.sn-file-browser-list::-webkit-scrollbar-thumb,
|
||||
.sn-selected-files-list::-webkit-scrollbar-thumb,
|
||||
.sn-recent-files-list::-webkit-scrollbar-thumb {
|
||||
background: var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.file-browser-list::-webkit-scrollbar-thumb:hover,
|
||||
.selected-files-list::-webkit-scrollbar-thumb:hover,
|
||||
.recent-files-list::-webkit-scrollbar-thumb:hover {
|
||||
.sn-file-browser-list::-webkit-scrollbar-thumb:hover,
|
||||
.sn-selected-files-list::-webkit-scrollbar-thumb:hover,
|
||||
.sn-recent-files-list::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--background-modifier-border-hover);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
/* Toast 알림 */
|
||||
.toast-container {
|
||||
.sn-toast-container {
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
pointer-events: none;
|
||||
|
|
@ -11,39 +11,39 @@
|
|||
max-width: 400px;
|
||||
}
|
||||
|
||||
.toast-container--top-right {
|
||||
.sn-toast-container--top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.toast-container--top-left {
|
||||
.sn-toast-container--top-left {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.toast-container--bottom-right {
|
||||
.sn-toast-container--bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.toast-container--bottom-left {
|
||||
.sn-toast-container--bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.toast-container--top-center {
|
||||
.sn-toast-container--top-center {
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.toast-container--bottom-center {
|
||||
.sn-toast-container--bottom-center {
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.toast {
|
||||
.sn-toast {
|
||||
pointer-events: auto;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
|
@ -59,92 +59,92 @@
|
|||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.toast--show {
|
||||
.sn-toast--show {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.toast--hide {
|
||||
.sn-toast--hide {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.toast-container--top-left .toast,
|
||||
.toast-container--bottom-left .toast {
|
||||
.sn-toast-container--top-left .sn-toast,
|
||||
.sn-toast-container--bottom-left .sn-toast {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.toast-container--top-left .toast--show,
|
||||
.toast-container--bottom-left .toast--show {
|
||||
.sn-toast-container--top-left .sn-toast--show,
|
||||
.sn-toast-container--bottom-left .sn-toast--show {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.toast-container--top-left .toast--hide,
|
||||
.toast-container--bottom-left .toast--hide {
|
||||
.sn-toast-container--top-left .sn-toast--hide,
|
||||
.sn-toast-container--bottom-left .sn-toast--hide {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.toast--success {
|
||||
.sn-toast--success {
|
||||
border-color: var(--text-success);
|
||||
}
|
||||
|
||||
.toast--error {
|
||||
.sn-toast--error {
|
||||
border-color: var(--text-error);
|
||||
}
|
||||
|
||||
.toast--warning {
|
||||
.sn-toast--warning {
|
||||
border-color: var(--text-warning);
|
||||
}
|
||||
|
||||
.toast--info {
|
||||
.sn-toast--info {
|
||||
border-color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.toast__icon {
|
||||
.sn-toast__icon {
|
||||
flex-shrink: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.toast--success .toast__icon {
|
||||
.sn-toast--success .sn-toast__icon {
|
||||
color: var(--text-success);
|
||||
}
|
||||
|
||||
.toast--error .toast__icon {
|
||||
.sn-toast--error .sn-toast__icon {
|
||||
color: var(--text-error);
|
||||
}
|
||||
|
||||
.toast--warning .toast__icon {
|
||||
.sn-toast--warning .sn-toast__icon {
|
||||
color: var(--text-warning);
|
||||
}
|
||||
|
||||
.toast--info .toast__icon {
|
||||
.sn-toast--info .sn-toast__icon {
|
||||
color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.toast__icon svg {
|
||||
.sn-toast__icon svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.toast__content {
|
||||
.sn-toast__content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.toast__title {
|
||||
.sn-toast__title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.toast__message {
|
||||
.sn-toast__message {
|
||||
color: var(--text-muted);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.toast__close {
|
||||
.sn-toast__close {
|
||||
flex-shrink: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
|
@ -158,17 +158,17 @@
|
|||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.toast__close:hover {
|
||||
.sn-toast__close:hover {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.toast__actions {
|
||||
.sn-toast__actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.toast__action {
|
||||
.sn-toast__action {
|
||||
padding: 4px 12px;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
|
|
@ -179,27 +179,27 @@
|
|||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.toast__action:hover {
|
||||
.sn-toast__action:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.toast__action--primary {
|
||||
.sn-toast__action--primary {
|
||||
background: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border-color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.toast__action--primary:hover {
|
||||
.sn-toast__action--primary:hover {
|
||||
background: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
.toast__action--danger {
|
||||
.sn-toast__action--danger {
|
||||
background: var(--text-error);
|
||||
color: white;
|
||||
border-color: var(--text-error);
|
||||
}
|
||||
|
||||
.toast__progress {
|
||||
.sn-toast__progress {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
|
@ -210,14 +210,14 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toast__progress-fill {
|
||||
.sn-toast__progress-fill {
|
||||
height: 100%;
|
||||
background: var(--interactive-accent);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
/* Modal 알림 */
|
||||
.modal-overlay {
|
||||
.sn-modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
@ -228,14 +228,14 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10001;
|
||||
animation: fadeIn 0.3s ease;
|
||||
animation: sn-notification-fade-in 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-overlay--hide {
|
||||
animation: fadeOut 0.3s ease;
|
||||
.sn-modal-overlay--hide {
|
||||
animation: sn-notification-fade-out 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
@keyframes sn-notification-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
|
@ -244,7 +244,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
@keyframes sn-notification-fade-out {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
@ -253,7 +253,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
.sn-modal {
|
||||
background: var(--background-primary);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
|
||||
|
|
@ -261,10 +261,10 @@
|
|||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow: auto;
|
||||
animation: slideIn 0.3s ease;
|
||||
animation: sn-notification-slide-in 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
@keyframes sn-notification-slide-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
|
|
@ -275,7 +275,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.modal__header {
|
||||
.sn-modal__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
|
@ -283,14 +283,14 @@
|
|||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.modal__title {
|
||||
.sn-modal__title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.modal__close {
|
||||
.sn-modal__close {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
|
|
@ -303,16 +303,16 @@
|
|||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.modal__close:hover {
|
||||
.sn-modal__close:hover {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.modal__content {
|
||||
.sn-modal__content {
|
||||
padding: 20px;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.modal__footer {
|
||||
.sn-modal__footer {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: flex-end;
|
||||
|
|
@ -320,7 +320,7 @@
|
|||
border-top: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.modal__action {
|
||||
.sn-modal__action {
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
|
|
@ -331,28 +331,28 @@
|
|||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.modal__action:hover {
|
||||
.sn-modal__action:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.modal__action--primary {
|
||||
.sn-modal__action--primary {
|
||||
background: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border-color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.modal__action--primary:hover {
|
||||
.sn-modal__action--primary:hover {
|
||||
background: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
.modal__action--danger {
|
||||
.sn-modal__action--danger {
|
||||
background: var(--text-error);
|
||||
color: white;
|
||||
border-color: var(--text-error);
|
||||
}
|
||||
|
||||
/* StatusBar 알림 */
|
||||
.status-bar {
|
||||
.sn-status-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
|
@ -366,53 +366,53 @@
|
|||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.status-bar--show {
|
||||
.sn-status-bar--show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.status-bar--success {
|
||||
.sn-status-bar--success {
|
||||
background: var(--text-success);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-bar--error {
|
||||
.sn-status-bar--error {
|
||||
background: var(--text-error);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-bar--warning {
|
||||
.sn-status-bar--warning {
|
||||
background: var(--text-warning);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-bar--info {
|
||||
.sn-status-bar--info {
|
||||
background: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
/* 원형 진행률 */
|
||||
.circular-progress {
|
||||
.sn-circular-progress {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.semi-circular-progress {
|
||||
.sn-semi-circular-progress {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 로딩 인디케이터 */
|
||||
.loading-spinner {
|
||||
.sn-loading-spinner {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.loading-spinner svg {
|
||||
animation: spin 1s linear infinite;
|
||||
.sn-loading-spinner svg {
|
||||
animation: sn-notification-spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
@keyframes sn-notification-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
|
@ -421,54 +421,54 @@
|
|||
}
|
||||
}
|
||||
|
||||
.loading-spinner--small svg {
|
||||
.sn-loading-spinner--small svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.loading-spinner--medium svg {
|
||||
.sn-loading-spinner--medium svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.loading-spinner--large svg {
|
||||
.sn-loading-spinner--large svg {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.loading-message {
|
||||
.sn-loading-message {
|
||||
color: var(--text-muted);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 펄스 로더 */
|
||||
.loading-pulse {
|
||||
.sn-loading-pulse {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.pulse-dot {
|
||||
.sn-pulse-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--interactive-accent);
|
||||
animation: pulse 1.5s ease-in-out infinite;
|
||||
animation: sn-notification-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.pulse-dot--1 {
|
||||
.sn-pulse-dot--1 {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.pulse-dot--2 {
|
||||
.sn-pulse-dot--2 {
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
|
||||
.pulse-dot--3 {
|
||||
.sn-pulse-dot--3 {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
@keyframes sn-notification-pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.3;
|
||||
|
|
@ -480,34 +480,34 @@
|
|||
}
|
||||
}
|
||||
|
||||
.loading-pulse--small .pulse-dot {
|
||||
.sn-loading-pulse--small .sn-pulse-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.loading-pulse--large .pulse-dot {
|
||||
.sn-loading-pulse--large .sn-pulse-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
/* 스켈레톤 로더 */
|
||||
.loading-skeleton {
|
||||
.sn-loading-skeleton {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.skeleton-line {
|
||||
.sn-skeleton-line {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
background: var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.skeleton-animated {
|
||||
.sn-skeleton-animated {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.skeleton-animated::after {
|
||||
.sn-skeleton-animated::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -515,76 +515,76 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
animation: shimmer 2s infinite;
|
||||
animation: sn-notification-shimmer 2s infinite;
|
||||
}
|
||||
|
||||
.loading-skeleton .skeleton-line:last-child {
|
||||
.sn-loading-skeleton .sn-skeleton-line:last-child {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.loading-skeleton--height-sm .skeleton-line {
|
||||
.sn-loading-skeleton--height-sm .sn-skeleton-line {
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.loading-skeleton--height-md .skeleton-line {
|
||||
.sn-loading-skeleton--height-md .sn-skeleton-line {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.loading-skeleton--height-lg .skeleton-line {
|
||||
.sn-loading-skeleton--height-lg .sn-skeleton-line {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.loading-skeleton--spacing-none .skeleton-line:not(:last-child) {
|
||||
.sn-loading-skeleton--spacing-none .sn-skeleton-line:not(:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.loading-skeleton--spacing-sm .skeleton-line:not(:last-child) {
|
||||
.sn-loading-skeleton--spacing-sm .sn-skeleton-line:not(:last-child) {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.loading-skeleton--spacing-md .skeleton-line:not(:last-child) {
|
||||
.sn-loading-skeleton--spacing-md .sn-skeleton-line:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.loading-skeleton--spacing-lg .skeleton-line:not(:last-child) {
|
||||
.sn-loading-skeleton--spacing-lg .sn-skeleton-line:not(:last-child) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
@keyframes sn-notification-shimmer {
|
||||
to {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 도트 로더 */
|
||||
.loading-dots {
|
||||
.sn-loading-dots {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.dots-container {
|
||||
.sn-dots-container {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.dot {
|
||||
.sn-dot {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
background: var(--text-muted);
|
||||
animation: dot-bounce 1.4s ease-in-out infinite;
|
||||
animation: sn-notification-dot-bounce 1.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.dot:nth-child(1) {
|
||||
.sn-dot:nth-child(1) {
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.dot:nth-child(2) {
|
||||
.sn-dot:nth-child(2) {
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
@keyframes dot-bounce {
|
||||
@keyframes sn-notification-dot-bounce {
|
||||
0%,
|
||||
60%,
|
||||
100% {
|
||||
|
|
@ -596,45 +596,45 @@
|
|||
}
|
||||
|
||||
/* 상태 아이콘 */
|
||||
.status-icon {
|
||||
.sn-status-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.status-icon__icon {
|
||||
.sn-status-icon__icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.status-icon__icon svg {
|
||||
.sn-status-icon__icon svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.status-icon--success .status-icon__icon {
|
||||
.sn-status-icon--success .sn-status-icon__icon {
|
||||
color: var(--text-success);
|
||||
}
|
||||
|
||||
.status-icon--error .status-icon__icon {
|
||||
.sn-status-icon--error .sn-status-icon__icon {
|
||||
color: var(--text-error);
|
||||
}
|
||||
|
||||
.status-icon--warning .status-icon__icon {
|
||||
.sn-status-icon--warning .sn-status-icon__icon {
|
||||
color: var(--text-warning);
|
||||
}
|
||||
|
||||
.status-icon--info .status-icon__icon {
|
||||
.sn-status-icon--info .sn-status-icon__icon {
|
||||
color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.status-icon__message {
|
||||
.sn-status-icon__message {
|
||||
color: var(--text-normal);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 스크린 리더 전용 */
|
||||
.sr-only {
|
||||
.sn-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
1220
styles.css
1220
styles.css
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue