refactor: split CSS and JS into modular files (SRP)

This commit is contained in:
2025-12-26 13:55:02 +01:00
parent 94cf36bff3
commit 2e5731b5d6
47 changed files with 8882 additions and 2298 deletions

View File

@@ -101,6 +101,94 @@ src/server/
Source: [src/server/](../src/server/)
### 2.2.1 Frontend Architecture (`src/server/web/static/`)
The frontend uses a modular architecture with no build step required. CSS and JavaScript files are organized by responsibility.
#### CSS Structure
```
src/server/web/static/css/
+-- styles.css # Entry point with @import statements
+-- base/
| +-- variables.css # CSS custom properties (colors, fonts, spacing)
| +-- reset.css # CSS reset and normalize styles
| +-- typography.css # Font styles, headings, text utilities
+-- components/
| +-- buttons.css # All button styles
| +-- cards.css # Card and panel components
| +-- forms.css # Form inputs, labels, validation styles
| +-- modals.css # Modal and overlay styles
| +-- navigation.css # Header, nav, sidebar styles
| +-- progress.css # Progress bars, loading indicators
| +-- notifications.css # Toast, alerts, messages
| +-- tables.css # Table and list styles
| +-- status.css # Status badges and indicators
+-- pages/
| +-- login.css # Login page specific styles
| +-- index.css # Index/library page specific styles
| +-- queue.css # Queue page specific styles
+-- utilities/
+-- animations.css # Keyframes and animation classes
+-- responsive.css # Media queries and breakpoints
+-- helpers.css # Utility classes (hidden, flex, spacing)
```
#### JavaScript Structure
JavaScript uses the IIFE pattern with a shared `AniWorld` namespace for browser compatibility without build tools.
```
src/server/web/static/js/
+-- shared/ # Shared utilities used by all pages
| +-- constants.js # API endpoints, localStorage keys, defaults
| +-- auth.js # Token management (getToken, setToken, checkAuth)
| +-- api-client.js # Fetch wrapper with auto-auth headers
| +-- theme.js # Dark/light theme toggle
| +-- ui-utils.js # Toast notifications, format helpers
| +-- websocket-client.js # Socket.IO wrapper
+-- index/ # Index page modules
| +-- series-manager.js # Series list rendering and filtering
| +-- selection-manager.js# Multi-select and bulk download
| +-- search.js # Series search functionality
| +-- scan-manager.js # Library rescan operations
| +-- scheduler-config.js # Scheduler configuration
| +-- logging-config.js # Logging configuration
| +-- advanced-config.js # Advanced settings
| +-- main-config.js # Main configuration and backup
| +-- config-manager.js # Config modal orchestrator
| +-- socket-handler.js # WebSocket event handlers
| +-- app-init.js # Application initialization
+-- queue/ # Queue page modules
+-- queue-api.js # Queue API interactions
+-- queue-renderer.js # Queue list rendering
+-- progress-handler.js # Download progress updates
+-- queue-socket-handler.js # WebSocket events for queue
+-- queue-init.js # Queue page initialization
```
#### Module Pattern
All JavaScript modules follow the IIFE pattern with namespace:
```javascript
var AniWorld = window.AniWorld || {};
AniWorld.ModuleName = (function () {
"use strict";
// Private variables and functions
// Public API
return {
init: init,
publicMethod: publicMethod,
};
})();
```
Source: [src/server/web/static/](../src/server/web/static/)
### 2.3 Core Layer (`src/core/`)
Domain logic for anime series management.

View File

@@ -106,149 +106,785 @@ For each task completed:
---
## Task: Refactor CSS & JavaScript Files (Single Responsibility Principle) ✅ COMPLETED
### Status: COMPLETED
The CSS and JavaScript files have been successfully refactored into modular structures.
### Summary of Changes
**CSS Refactoring:**
- Created 17 modular CSS files organized into `base/`, `components/`, `pages/`, and `utilities/` directories
- `styles.css` now serves as an entry point with @import statements
- All CSS files under 500 lines (largest: helpers.css at 368 lines)
- Total: 3,146 lines across 17 files
**JavaScript Refactoring:**
- Created 6 shared utility modules in `js/shared/`
- Created 11 index page modules in `js/index/`
- Created 5 queue page modules in `js/queue/`
- Uses IIFE pattern with `AniWorld` namespace for browser compatibility
- All JS files under 500 lines (largest: scan-manager.js at 439 lines)
- Total: 4,795 lines across 22 modules
**Updated Files:**
- `index.html` - Updated script tags for modular JS
- `queue.html` - Updated script tags for modular JS
- `test_static_files.py` - Updated tests for modular architecture
- `test_template_integration.py` - Updated tests for new JS structure
- `ARCHITECTURE.md` - Added frontend architecture documentation
**Old Files (kept for reference):**
- `app.js` - Original monolithic file (can be deleted)
- `queue.js` - Original monolithic file (can be deleted)
### Original Overview
Split monolithic `styles.css` (~2,135 lines), `app.js` (~2,305 lines), and `queue.js` (~993 lines) into smaller, focused files following the Single Responsibility Principle. Maximum 500 lines per file. All changes must maintain full backward compatibility with existing templates.
### Prerequisites
1. Server is running: `conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app --host 127.0.0.1 --port 8000 --reload`
2. Password: `Hallo123!`
3. Login via browser at `http://127.0.0.1:8000/login`
### Notes
- This is a simplification that removes complexity while maintaining core functionality
- Improves user experience with explicit manual control
- Easier to understand, test, and maintain
- Good foundation for future enhancements if needed
- Server is running and functional before starting
- All existing functionality works (login, index, queue pages)
- Backup current files before making changes
---
## Task: Enhanced Anime Add Flow ✅ COMPLETED
### Task 1: Analyze Current File Structure
### Overview
**Objective**: Understand the current codebase before making changes.
Enhance the anime addition workflow to automatically persist anime to the database, scan for missing episodes immediately, and create folders using the anime display name instead of the internal key.
**Steps**:
### Requirements
1. Open and read `src/server/web/static/css/styles.css`
2. Open and read `src/server/web/static/js/app.js`
3. Open and read `src/server/web/static/js/queue.js`
4. Open and read `src/server/web/templates/index.html`
5. Open and read `src/server/web/templates/queue.html`
6. Open and read `src/server/web/templates/login.html`
7. Document all CSS sections (look for comment headers)
8. Document all JavaScript functions and their dependencies
9. Identify shared utilities vs page-specific code
1. **After anime add → Save to database**: Ensure the anime is persisted to the database via `AnimeDBService.create_series()` immediately after validation
2. **After anime add → Scan for missing episodes**: Trigger a targeted episode scan for only the newly added anime (not the entire library)
3. **After anime add → Create folder with anime name**: Use the anime display name (sanitized) for the folder, not the anime key
### Implementation Steps
#### Step 1: Examine Current Implementation
1. Open and read `src/server/routes/anime_routes.py` - find the `add_series` endpoint
2. Open and read `src/core/SerieScanner.py` - understand how scanning works
3. Open and read `src/core/entities/Serie.py` and `src/core/entities/SerieList.py` - understand folder handling
4. Open and read `src/database/services/anime_db_service.py` - understand database operations
5. Open and read `src/core/providers/AniWorldProvider.py` - understand how folders are created
#### Step 2: Create Utility Function for Folder Name Sanitization
1. Create or update utility module at `src/utils/filesystem.py`
2. Implement `sanitize_folder_name(name: str) -> str` function that:
- Removes/replaces characters invalid for filesystems: `< > : " / \ | ? *`
- Trims leading/trailing whitespace and dots
- Handles edge cases (empty string, only invalid chars)
- Preserves Unicode characters (for Japanese titles, etc.)
#### Step 3: Update Serie Entity
1. Open `src/core/entities/Serie.py`
2. Add a `folder` property that returns sanitized display name instead of key
3. Ensure backward compatibility with existing series
#### Step 4: Update SerieList to Use Display Name for Folders
1. Open `src/core/entities/SerieList.py`
2. In the `add()` method, use `serie.folder` (display name) instead of `serie.key` when creating directories
3. Ensure the folder path is correctly stored in the Serie object
#### Step 5: Add Targeted Episode Scan Method to SerieScanner
1. Open `src/core/SerieScanner.py`
2. Add new method `scan_single_series(self, key: str) -> List[Episode]`:
- Fetches the specific anime from database/SerieList by key
- Calls the provider to get available episodes
- Compares with local files to find missing episodes
- Returns list of missing episodes
- Does NOT trigger a full library rescan
#### Step 6: Update add_series Endpoint
1. Open `src/server/routes/anime_routes.py`
2. Modify the `add_series` endpoint to:
- **Step A**: Validate the request (existing)
- **Step B**: Create Serie object with sanitized folder name
- **Step C**: Save to database via `AnimeDBService.create_series()`
- **Step D**: Add to SerieList (which creates the folder)
- **Step E**: Call `SerieScanner.scan_single_series(key)` for targeted scan
- **Step F**: Return response including:
- Success status
- Created folder path
- List of missing episodes found (if any)
#### Step 7: Update Provider Folder Handling
1. Open `src/core/providers/AniWorldProvider.py`
2. Ensure download operations use `serie.folder` for filesystem paths
3. If `EnhancedProvider.py` exists, update it similarly
### Acceptance Criteria
- [x] When adding a new anime, it is immediately saved to the database
- [x] When adding a new anime, only that anime is scanned for missing episodes (not full library)
- [x] Folder is created using the sanitized display name (e.g., "Attack on Titan" not "attack-on-titan")
- [x] Special characters in anime names are properly handled (`:`, `?`, etc.)
- [x] Existing anime entries continue to work (backward compatibility)
- [x] API response includes the created folder path and missing episodes count
- [x] Unit tests cover the new functionality
- [x] No regressions in existing tests
### Implementation Summary (Completed)
**Files Created/Modified:**
- `src/server/utils/filesystem.py` - New file with `sanitize_folder_name()`, `is_safe_path()`, `create_safe_folder()`
- `src/core/entities/series.py` - Added `sanitized_folder` property
- `src/core/entities/SerieList.py` - Updated `add()` to use sanitized folder names
- `src/core/SerieScanner.py` - Added `scan_single_series()` method
- `src/server/api/anime.py` - Enhanced `add_series` endpoint with full flow
**Tests Added:**
- `tests/unit/test_filesystem_utils.py` - 43 tests for filesystem utilities
- `tests/unit/test_serie_class.py` - 6 tests for `sanitized_folder` property
- `tests/unit/test_serie_scanner.py` - 9 tests for `scan_single_series()`
- `tests/api/test_anime_endpoints.py` - 6 integration tests for enhanced add flow
**All 97 related tests passing. No regressions in existing 848 unit tests and 60 API tests.**
### Testing Requirements
1. **Unit Tests**:
- Test `sanitize_folder_name()` with various inputs (special chars, Unicode, edge cases)
- Test `Serie.folder` property returns sanitized name
- Test `SerieScanner.scan_single_series()` only scans the specified anime
- Test database persistence on anime add
2. **Integration Tests**:
- Test full add flow: request → database → folder creation → scan
- Test that folder is created with correct name
- Test API response contains expected fields
### Error Handling
- If database save fails, return appropriate error and don't create folder
- If folder creation fails (permissions, disk full), return error and rollback database entry
- If scan fails, still return success for add but indicate scan failure in response
- Log all operations with appropriate log levels
### Security Considerations
- Sanitize folder names to prevent path traversal attacks
- Validate anime name length to prevent filesystem issues
- Ensure folder is created within the configured library path only
**Deliverable**: A mental map of all functions, styles, and their relationships.
---
### Task 2: Create CSS Directory Structure
**Objective**: Set up the new CSS file organization.
**Steps**:
1. Create directory: `src/server/web/static/css/base/`
2. Create directory: `src/server/web/static/css/components/`
3. Create directory: `src/server/web/static/css/pages/`
4. Create directory: `src/server/web/static/css/utilities/`
**File Structure to Create**:
```
src/server/web/static/css/
├── styles.css # Main entry point with @import statements
├── base/
│ ├── variables.css # CSS custom properties (colors, fonts, spacing)
│ ├── reset.css # CSS reset and normalize styles
│ └── typography.css # Font styles, headings, text utilities
├── components/
│ ├── buttons.css # All button styles
│ ├── cards.css # Card and panel components
│ ├── forms.css # Form inputs, labels, validation styles
│ ├── modals.css # Modal and overlay styles
│ ├── navigation.css # Header, nav, sidebar styles
│ ├── progress.css # Progress bars, loading indicators
│ ├── notifications.css # Toast, alerts, messages
│ └── tables.css # Table and list styles
├── pages/
│ ├── login.css # Login page specific styles
│ ├── index.css # Index/library page specific styles
│ └── queue.css # Queue page specific styles
└── utilities/
├── animations.css # Keyframes and animation classes
├── responsive.css # Media queries and breakpoints
└── helpers.css # Utility classes (hidden, flex, spacing)
```
---
### Task 3: Split styles.css into Modular Files
**Objective**: Extract styles from `styles.css` into appropriate module files.
**Steps**:
1. **Extract variables.css**:
- Find all `:root` CSS custom properties
- Extract color variables, font variables, spacing variables
- Include dark mode variables (`.dark-mode` or `[data-theme="dark"]`)
2. **Extract reset.css**:
- Extract `*`, `body`, `html` base resets
- Extract box-sizing rules
- Extract default margin/padding resets
3. **Extract typography.css**:
- Extract `h1-h6` styles
- Extract paragraph, link, text styles
- Extract font-related utility classes
4. **Extract buttons.css**:
- Find all `.btn`, `button`, `.button` related styles
- Include hover, active, disabled states
- Include button variants (primary, secondary, danger, etc.)
5. **Extract cards.css**:
- Extract `.card`, `.panel`, `.box` related styles
- Include card headers, bodies, footers
6. **Extract forms.css**:
- Extract `input`, `select`, `textarea` styles
- Extract `.form-group`, `.form-control` styles
- Extract validation states (error, success)
7. **Extract modals.css**:
- Extract `.modal`, `.overlay`, `.dialog` styles
- Include backdrop styles
- Include modal animations
8. **Extract navigation.css**:
- Extract `header`, `nav`, `.navbar` styles
- Extract menu and navigation link styles
9. **Extract progress.css**:
- Extract `.progress`, `.progress-bar` styles
- Extract loading spinners and indicators
10. **Extract notifications.css**:
- Extract `.toast`, `.alert`, `.notification` styles
- Include success, error, warning, info variants
11. **Extract tables.css**:
- Extract `table`, `.table` styles
- Extract list styles if table-like
12. **Extract page-specific styles**:
- `login.css`: Styles only used on login page
- `index.css`: Styles only used on index/library page (series cards, search)
- `queue.css`: Styles only used on queue page (queue items, download status)
13. **Extract animations.css**:
- Extract all `@keyframes` rules
- Extract animation utility classes
14. **Extract responsive.css**:
- Extract all `@media` queries
- Organize by breakpoint
15. **Extract helpers.css**:
- Extract utility classes (.hidden, .flex, .text-center, etc.)
- Extract spacing utilities
16. **Update main styles.css**:
- Replace all content with `@import` statements
- Order imports correctly (variables first, then reset, then components)
**Import Order in styles.css**:
```css
/* Base */
@import "base/variables.css";
@import "base/reset.css";
@import "base/typography.css";
/* Components */
@import "components/buttons.css";
@import "components/cards.css";
@import "components/forms.css";
@import "components/modals.css";
@import "components/navigation.css";
@import "components/progress.css";
@import "components/notifications.css";
@import "components/tables.css";
/* Pages */
@import "pages/login.css";
@import "pages/index.css";
@import "pages/queue.css";
/* Utilities (load last to allow overrides) */
@import "utilities/animations.css";
@import "utilities/responsive.css";
@import "utilities/helpers.css";
```
**Verification**:
- Start the server
- Check login page styling
- Check index page styling
- Check queue page styling
- Verify dark mode toggle works
- Verify responsive design works
---
### Task 4: Create JavaScript Directory Structure
**Objective**: Set up the new JavaScript file organization.
**Steps**:
1. Create directory: `src/server/web/static/js/shared/`
2. Create directory: `src/server/web/static/js/index/`
3. Create directory: `src/server/web/static/js/queue/`
**File Structure to Create**:
```
src/server/web/static/js/
├── app.js # Main entry point for index page
├── queue.js # Main entry point for queue page
├── shared/
│ ├── auth.js # Authentication utilities
│ ├── api-client.js # HTTP request wrapper with auth
│ ├── websocket-client.js # WebSocket connection management
│ ├── theme.js # Dark/light mode management
│ ├── ui-utils.js # Toast, loading overlay, formatters
│ └── constants.js # Shared constants and config
├── index/
│ ├── series-manager.js # Series loading, filtering, rendering
│ ├── search.js # Search functionality
│ ├── scan-manager.js # Library scan operations
│ ├── config-manager.js # Configuration modal handling
│ └── selection.js # Series/episode selection logic
└── queue/
├── queue-api.js # Queue API operations
├── queue-renderer.js # Render queue items (pending, active, etc.)
└── progress-handler.js # Real-time progress updates
```
---
### Task 5: Extract Shared JavaScript Utilities
**Objective**: Create reusable utility modules used by both index and queue pages.
**Steps**:
1. **Create constants.js**:
- Extract API endpoint URLs
- Extract localStorage keys
- Extract any magic strings or numbers
2. **Create auth.js**:
- Extract `checkAuth()` function
- Extract `logout()` function
- Extract `getAuthHeaders()` or token retrieval logic
- Extract token storage/retrieval from localStorage
3. **Create api-client.js**:
- Extract `fetchWithAuth()` wrapper function
- Handle automatic token injection
- Handle 401 redirect to login
- Handle common error responses
4. **Create websocket-client.js**:
- Extract WebSocket connection setup
- Extract message handling dispatcher
- Extract reconnection logic
- Extract connection state management
5. **Create theme.js**:
- Extract `initTheme()` function
- Extract `toggleTheme()` function
- Extract `setTheme()` function
- Extract theme persistence to localStorage
6. **Create ui-utils.js**:
- Extract `showToast()` function
- Extract `showLoadingOverlay()` / `hideLoadingOverlay()`
- Extract `formatBytes()` function
- Extract `formatDuration()` function
- Extract `formatDate()` function
- Extract any other shared UI helpers
**Pattern to Use (IIFE with Global Namespace)**:
```javascript
// Example: shared/auth.js
var AniWorld = window.AniWorld || {};
AniWorld.Auth = (function () {
"use strict";
const TOKEN_KEY = "auth_token";
function getToken() {
return localStorage.getItem(TOKEN_KEY);
}
function setToken(token) {
localStorage.setItem(TOKEN_KEY, token);
}
function removeToken() {
localStorage.removeItem(TOKEN_KEY);
}
function getAuthHeaders() {
const token = getToken();
return token ? { Authorization: "Bearer " + token } : {};
}
async function checkAuth() {
// Implementation
}
function logout() {
removeToken();
window.location.href = "/login";
}
// Public API
return {
getToken: getToken,
setToken: setToken,
getAuthHeaders: getAuthHeaders,
checkAuth: checkAuth,
logout: logout,
};
})();
```
---
### Task 6: Split app.js into Index Page Modules
**Objective**: Break down `app.js` into focused modules for the index/library page.
**Steps**:
1. **Create series-manager.js**:
- Extract series loading from API
- Extract series filtering logic
- Extract series rendering/DOM updates
- Extract series card click handlers
2. **Create search.js**:
- Extract search input handling
- Extract search API calls
- Extract search results rendering
- Extract search result selection
3. **Create scan-manager.js**:
- Extract scan initiation logic
- Extract scan progress overlay
- Extract scan progress updates (WebSocket)
- Extract scan completion handling
4. **Create config-manager.js**:
- Extract config modal open/close
- Extract config loading from API
- Extract config form handling
- Extract config save logic
- Extract scheduler configuration
- Extract backup management
5. **Create selection.js**:
- Extract episode selection logic
- Extract "select all" functionality
- Extract selection state management
- Extract "add to queue" from selection
6. **Update main app.js**:
- Import all modules via script tags
- Initialize all modules on DOMContentLoaded
- Wire up event listeners to module functions
- Keep this file as thin as possible (orchestration only)
**Example main app.js structure**:
```javascript
// filepath: src/server/web/static/js/app.js
document.addEventListener("DOMContentLoaded", async function () {
"use strict";
// Initialize shared modules
AniWorld.Theme.init();
// Check authentication
const isAuth = await AniWorld.Auth.checkAuth();
if (!isAuth) return;
// Initialize page-specific modules
AniWorld.SeriesManager.init();
AniWorld.Search.init();
AniWorld.ScanManager.init();
AniWorld.ConfigManager.init();
AniWorld.Selection.init();
// Initialize WebSocket for real-time updates
AniWorld.WebSocketClient.init();
// Load initial data
AniWorld.SeriesManager.loadSeries();
});
```
---
### Task 7: Split queue.js into Queue Page Modules
**Objective**: Break down `queue.js` into focused modules for the queue page.
**Steps**:
1. **Create queue-api.js**:
- Extract `loadQueueStatus()` API call
- Extract `startDownload()` API call
- Extract `stopDownload()` API call
- Extract `removeFromQueue()` API call
- Extract `clearCompleted()` API call
- Extract `clearFailed()` API call
- Extract `retryFailed()` API call
2. **Create queue-renderer.js**:
- Extract `renderActiveDownload()` function
- Extract `renderPendingQueue()` function
- Extract `renderCompletedList()` function
- Extract `renderFailedList()` function
- Extract `updateQueueCounts()` function
- Extract queue item template generation
3. **Create progress-handler.js**:
- Extract WebSocket message handling for queue
- Extract progress bar updates
- Extract status text updates
- Extract ETA calculations
- Extract speed display formatting
4. **Update main queue.js**:
- Import all modules via script tags
- Initialize all modules on DOMContentLoaded
- Wire up button click handlers to API functions
- Set up WebSocket handlers for progress
- Keep this file as thin as possible
**Example main queue.js structure**:
```javascript
// filepath: src/server/web/static/js/queue.js
document.addEventListener("DOMContentLoaded", async function () {
"use strict";
// Initialize shared modules
AniWorld.Theme.init();
// Check authentication
const isAuth = await AniWorld.Auth.checkAuth();
if (!isAuth) return;
// Initialize queue modules
AniWorld.QueueApi.init();
AniWorld.QueueRenderer.init();
AniWorld.ProgressHandler.init();
// Initialize WebSocket with queue-specific handlers
AniWorld.WebSocketClient.init({
onProgress: AniWorld.ProgressHandler.handleProgress,
onQueueUpdate: AniWorld.QueueRenderer.refresh,
});
// Load initial queue status
await AniWorld.QueueApi.loadStatus();
AniWorld.QueueRenderer.refresh();
// Wire up UI buttons
document
.getElementById("start-btn")
?.addEventListener("click", AniWorld.QueueApi.startDownload);
document
.getElementById("stop-btn")
?.addEventListener("click", AniWorld.QueueApi.stopDownload);
document
.getElementById("clear-completed-btn")
?.addEventListener("click", AniWorld.QueueApi.clearCompleted);
document
.getElementById("clear-failed-btn")
?.addEventListener("click", AniWorld.QueueApi.clearFailed);
});
```
---
### Task 8: Update HTML Templates
**Objective**: Update templates to load the new modular JavaScript files.
**Steps**:
1. **Update index.html**:
- Add script tags for shared modules (in order)
- Add script tags for index-specific modules (in order)
- Keep main app.js as the last script
- Ensure correct load order (dependencies first)
```html
<!-- Shared Modules -->
<script src="/static/js/shared/constants.js"></script>
<script src="/static/js/shared/auth.js"></script>
<script src="/static/js/shared/api-client.js"></script>
<script src="/static/js/shared/websocket-client.js"></script>
<script src="/static/js/shared/theme.js"></script>
<script src="/static/js/shared/ui-utils.js"></script>
<!-- Index Page Modules -->
<script src="/static/js/index/series-manager.js"></script>
<script src="/static/js/index/search.js"></script>
<script src="/static/js/index/scan-manager.js"></script>
<script src="/static/js/index/config-manager.js"></script>
<script src="/static/js/index/selection.js"></script>
<!-- Main Entry Point -->
<script src="/static/js/app.js"></script>
```
2. **Update queue.html**:
- Add script tags for shared modules (in order)
- Add script tags for queue-specific modules (in order)
- Keep main queue.js as the last script
```html
<!-- Shared Modules -->
<script src="/static/js/shared/constants.js"></script>
<script src="/static/js/shared/auth.js"></script>
<script src="/static/js/shared/api-client.js"></script>
<script src="/static/js/shared/websocket-client.js"></script>
<script src="/static/js/shared/theme.js"></script>
<script src="/static/js/shared/ui-utils.js"></script>
<!-- Queue Page Modules -->
<script src="/static/js/queue/queue-api.js"></script>
<script src="/static/js/queue/queue-renderer.js"></script>
<script src="/static/js/queue/progress-handler.js"></script>
<!-- Main Entry Point -->
<script src="/static/js/queue.js"></script>
```
3. **Update login.html** (if applicable):
- Only include shared modules needed for login
- Likely just theme.js and minimal utilities
---
### Task 9: Verification and Testing
**Objective**: Ensure all functionality works after refactoring.
**Steps**:
1. **Start the server**:
```bash
conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app --host 127.0.0.1 --port 8000 --reload
```
2. **Test Login Page**:
- [ ] Page loads with correct styling
- [ ] Dark/light mode toggle works
- [ ] Login form submits correctly
- [ ] Error messages display correctly
- [ ] Successful login redirects to index
3. **Test Index Page**:
- [ ] Page loads with correct styling
- [ ] Series list loads and displays
- [ ] Series filtering works
- [ ] Search functionality works
- [ ] Series selection works
- [ ] Episode selection works
- [ ] Add to queue works
- [ ] Scan library works
- [ ] Scan progress displays
- [ ] Config modal opens/closes
- [ ] Config saves correctly
- [ ] Dark/light mode toggle works
- [ ] Logout works
- [ ] WebSocket connection established
4. **Test Queue Page**:
- [ ] Page loads with correct styling
- [ ] Queue status loads
- [ ] Pending items display
- [ ] Active download displays
- [ ] Completed items display
- [ ] Failed items display
- [ ] Start download works
- [ ] Stop download works
- [ ] Remove from queue works
- [ ] Clear completed works
- [ ] Clear failed works
- [ ] Retry failed works
- [ ] Progress updates in real-time
- [ ] Dark/light mode toggle works
- [ ] WebSocket connection established
5. **Test Responsive Design**:
- [ ] All pages work on mobile viewport
- [ ] All pages work on tablet viewport
- [ ] All pages work on desktop viewport
6. **Browser Console Check**:
- [ ] No JavaScript errors in console
- [ ] No 404 errors for static files
- [ ] No CSS loading errors
---
### Task 10: Cleanup and Documentation
**Objective**: Finalize the refactoring with cleanup and documentation.
**Steps**:
1. **Remove backup files** (if any were created)
2. **Verify file sizes**:
- No file should exceed 500 lines
- If any file exceeds, split further
3. **Add file headers**:
- Add comment header to each new file explaining its purpose
```javascript
/**
* AniWorld - Series Manager Module
*
* Handles loading, filtering, and rendering of anime series
* on the index/library page.
*
* Dependencies: auth.js, api-client.js, ui-utils.js
*/
```
```css
/**
* AniWorld - Button Styles
*
* All button-related styles including variants,
* states, and sizes.
*/
```
4. **Update infrastructure.md** (if exists):
- Document new file structure
- Document module dependencies
5. **Commit changes**:
```bash
git add .
git commit -m "refactor: split CSS and JS into modular files (SRP)"
```
---
### Summary of New Files
**CSS Files (14 files)**:
- `css/styles.css` (entry point with imports)
- `css/base/variables.css`
- `css/base/reset.css`
- `css/base/typography.css`
- `css/components/buttons.css`
- `css/components/cards.css`
- `css/components/forms.css`
- `css/components/modals.css`
- `css/components/navigation.css`
- `css/components/progress.css`
- `css/components/notifications.css`
- `css/components/tables.css`
- `css/pages/login.css`
- `css/pages/index.css`
- `css/pages/queue.css`
- `css/utilities/animations.css`
- `css/utilities/responsive.css`
- `css/utilities/helpers.css`
**JavaScript Files (15 files)**:
- `js/app.js` (entry point for index)
- `js/queue.js` (entry point for queue)
- `js/shared/constants.js`
- `js/shared/auth.js`
- `js/shared/api-client.js`
- `js/shared/websocket-client.js`
- `js/shared/theme.js`
- `js/shared/ui-utils.js`
- `js/index/series-manager.js`
- `js/index/search.js`
- `js/index/scan-manager.js`
- `js/index/config-manager.js`
- `js/index/selection.js`
- `js/queue/queue-api.js`
- `js/queue/queue-renderer.js`
- `js/queue/progress-handler.js`
---
### Important Notes
1. **IIFE Pattern**: Use the IIFE (Immediately Invoked Function Expression) pattern with a global namespace (`AniWorld`) for browser compatibility without requiring a build step.
2. **No Build Tools Required**: This approach uses native CSS `@import` and multiple `<script>` tags, avoiding the need for bundlers like Webpack or Vite.
3. **Load Order Matters**: Scripts must be loaded in dependency order. Shared modules first, then page-specific modules, then the main entry point.
4. **Backward Compatibility**: All existing HTML element IDs and class names must be preserved. Only the JavaScript and CSS organization changes, not the API.
5. **Incremental Approach**: Complete one task fully before moving to the next. Verify functionality after each major step.
6. **Rollback Plan**: Keep the original files until all verification is complete. Only delete originals after confirming everything works.