mirror of
https://github.com/thecyberlearn/modern-django-starter.git
synced 2026-08-18 06:52:54 +00:00
Migrate from Bootstrap to Tailwind CSS with comprehensive UI improvements
This commit represents a complete migration from Bootstrap to Tailwind CSS with modern, professional UI design: ## Major Changes: - **Tailwind CSS Integration**: Added django-tailwind package with Node.js 18.x support - **UI Redesign**: Complete template migration to modern black/white theme - **Responsive Design**: Mobile-first approach with improved navigation - **Database Enhancement**: Added DATABASE_URL support for external services (Neon, Supabase, Railway, etc.) - **Documentation**: Updated README.md and DEPLOYMENT.md with Tailwind and database guidance ## Technical Improvements: - Hot-reloading during development with django-browser-reload - Production-optimized CSS builds with purging and minification - Professional card layouts and components - Sticky footer implementation - Mobile-responsive navigation with hamburger menu - Modern alert/message styling ## Files Modified: - All HTML templates converted to Tailwind utility classes - Added theme app with Tailwind configuration - Updated Docker configuration for Node.js support - Enhanced settings for third-party database services - Comprehensive documentation updates 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
85f68a8df9
commit
cde04c8dbe
20
.env.example
20
.env.example
@ -4,11 +4,31 @@ DEBUG=True
|
||||
ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0
|
||||
|
||||
# Database Configuration
|
||||
# Option 1: Individual variables (for Docker Compose/local development)
|
||||
DB_NAME=django_db
|
||||
DB_USER=django_user
|
||||
DB_PASSWORD=django_password
|
||||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
DB_SSLMODE=prefer
|
||||
|
||||
# Option 2: DATABASE_URL (for external services like Neon, Heroku, Railway, etc.)
|
||||
# Uncomment and use ONE of the following examples:
|
||||
|
||||
# Neon (https://neon.tech)
|
||||
# DATABASE_URL=postgresql://user:password@ep-xxx.us-east-1.aws.neon.tech/database?sslmode=require
|
||||
|
||||
# Supabase (https://supabase.com)
|
||||
# DATABASE_URL=postgresql://postgres:password@db.xxx.supabase.co:5432/postgres?sslmode=require
|
||||
|
||||
# Railway (https://railway.app)
|
||||
# DATABASE_URL=postgresql://postgres:password@containers-us-west-xxx.railway.app:5432/railway
|
||||
|
||||
# Heroku Postgres
|
||||
# DATABASE_URL=postgres://user:password@host:5432/database
|
||||
|
||||
# Amazon RDS
|
||||
# DATABASE_URL=postgresql://user:password@your-rds-instance.amazonaws.com:5432/database
|
||||
|
||||
# Email Configuration (for production)
|
||||
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
|
||||
|
||||
125
DEPLOYMENT.md
125
DEPLOYMENT.md
@ -71,6 +71,9 @@ Dokploy is a modern deployment platform that makes it easy to deploy application
|
||||
python manage.py migrate
|
||||
python manage.py create_groups
|
||||
python manage.py createsuperuser
|
||||
|
||||
# Build Tailwind CSS for production
|
||||
python manage.py tailwind build
|
||||
python manage.py collectstatic --noinput
|
||||
```
|
||||
|
||||
@ -82,6 +85,44 @@ Dokploy is a modern deployment platform that makes it easy to deploy application
|
||||
- Configure Google OAuth2 callback URL: `https://your-domain.com/accounts/google/login/callback/`
|
||||
- Configure Facebook OAuth2 callback URL: `https://your-domain.com/accounts/facebook/login/callback/`
|
||||
|
||||
## 🗄️ External Database Services
|
||||
|
||||
Instead of setting up your own PostgreSQL instance, you can use managed database services:
|
||||
|
||||
### Neon (Recommended)
|
||||
|
||||
1. **Create account** at [neon.tech](https://neon.tech)
|
||||
2. **Create a database** in your Neon dashboard
|
||||
3. **Copy connection string** from the dashboard
|
||||
4. **Set environment variable:**
|
||||
```env
|
||||
DATABASE_URL=postgresql://user:password@ep-xxx.us-east-1.aws.neon.tech/database?sslmode=require
|
||||
```
|
||||
|
||||
### Supabase
|
||||
|
||||
1. **Create project** at [supabase.com](https://supabase.com)
|
||||
2. **Go to Settings > Database**
|
||||
3. **Use connection pooler URL for production:**
|
||||
```env
|
||||
DATABASE_URL=postgresql://postgres:password@db.xxx.supabase.co:6543/postgres?sslmode=require
|
||||
```
|
||||
|
||||
### Railway
|
||||
|
||||
1. **Connect GitHub repo** to Railway
|
||||
2. **Add PostgreSQL service**
|
||||
3. **Railway sets DATABASE_URL automatically**
|
||||
|
||||
### Amazon RDS
|
||||
|
||||
1. **Create RDS PostgreSQL instance**
|
||||
2. **Configure security groups** for your application
|
||||
3. **Set DATABASE_URL with RDS endpoint:**
|
||||
```env
|
||||
DATABASE_URL=postgresql://user:password@your-rds.amazonaws.com:5432/database
|
||||
```
|
||||
|
||||
### Environment Variables Reference
|
||||
|
||||
| Variable | Description | Required | Default |
|
||||
@ -89,11 +130,13 @@ Dokploy is a modern deployment platform that makes it easy to deploy application
|
||||
| `SECRET_KEY` | Django secret key | Yes | - |
|
||||
| `DEBUG` | Debug mode | Yes | False |
|
||||
| `ALLOWED_HOSTS` | Allowed hostnames | Yes | - |
|
||||
| `DB_NAME` | Database name | Yes | django_db |
|
||||
| `DB_USER` | Database user | Yes | django_user |
|
||||
| `DB_PASSWORD` | Database password | Yes | - |
|
||||
| `DB_HOST` | Database host | Yes | postgres |
|
||||
| `DB_PORT` | Database port | Yes | 5432 |
|
||||
| `DATABASE_URL` | Full database URL | No* | - |
|
||||
| `DB_NAME` | Database name | No* | django_db |
|
||||
| `DB_USER` | Database user | No* | django_user |
|
||||
| `DB_PASSWORD` | Database password | No* | - |
|
||||
| `DB_HOST` | Database host | No* | postgres |
|
||||
| `DB_PORT` | Database port | No* | 5432 |
|
||||
| `DB_SSLMODE` | SSL mode for database | No | prefer |
|
||||
| `EMAIL_HOST` | SMTP host | No | localhost |
|
||||
| `EMAIL_PORT` | SMTP port | No | 587 |
|
||||
| `EMAIL_HOST_USER` | SMTP username | No | - |
|
||||
@ -103,6 +146,8 @@ Dokploy is a modern deployment platform that makes it easy to deploy application
|
||||
| `FACEBOOK_APP_ID` | Facebook app ID | No | - |
|
||||
| `FACEBOOK_APP_SECRET` | Facebook app secret | No | - |
|
||||
|
||||
**Note:** Either `DATABASE_URL` OR the individual `DB_*` variables are required, not both.
|
||||
|
||||
## 🐳 Docker Deployment
|
||||
|
||||
### Production Docker Compose
|
||||
@ -227,6 +272,64 @@ Consider adding:
|
||||
docker-compose -f docker-compose.prod.yml exec web python manage.py migrate
|
||||
```
|
||||
|
||||
4. **Rebuild Tailwind CSS:**
|
||||
```bash
|
||||
docker-compose -f docker-compose.prod.yml exec web python manage.py tailwind build
|
||||
docker-compose -f docker-compose.prod.yml exec web python manage.py collectstatic --noinput
|
||||
```
|
||||
|
||||
## 🎨 Tailwind CSS Production Considerations
|
||||
|
||||
### Building CSS for Production
|
||||
|
||||
The project uses `django-tailwind` which requires Node.js to build CSS files:
|
||||
|
||||
1. **Ensure Node.js is available in production:**
|
||||
```dockerfile
|
||||
# Dockerfile already includes Node.js installation
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
|
||||
&& apt-get install -y nodejs
|
||||
```
|
||||
|
||||
2. **Build process in CI/CD:**
|
||||
```bash
|
||||
# Install dependencies
|
||||
python manage.py tailwind install
|
||||
|
||||
# Build production CSS
|
||||
python manage.py tailwind build
|
||||
|
||||
# Collect static files
|
||||
python manage.py collectstatic --noinput
|
||||
```
|
||||
|
||||
3. **CSS Optimization:**
|
||||
- Production builds are automatically minified
|
||||
- Unused CSS is purged based on template scanning
|
||||
- CSS files are versioned for cache busting
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Add these to your production environment:
|
||||
|
||||
```env
|
||||
# Tailwind CSS
|
||||
TAILWIND_APP_NAME=theme
|
||||
NODE_ENV=production
|
||||
```
|
||||
|
||||
### Static Files Structure
|
||||
|
||||
After deployment, verify this structure:
|
||||
```
|
||||
/app/static/
|
||||
├── css/
|
||||
│ └── dist/
|
||||
│ └── styles.css # Built Tailwind CSS
|
||||
├── js/
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Backup Strategy
|
||||
|
||||
1. **Database backup:**
|
||||
@ -261,6 +364,18 @@ Consider adding:
|
||||
- Check firewall/security group settings
|
||||
- Test email backend configuration
|
||||
|
||||
5. **Tailwind CSS not loading:**
|
||||
- Verify Node.js is installed: `node --version`
|
||||
- Check if CSS was built: `ls -la static/css/dist/`
|
||||
- Rebuild CSS: `python manage.py tailwind build`
|
||||
- Ensure static files are collected: `python manage.py collectstatic`
|
||||
|
||||
6. **Styling looks broken:**
|
||||
- Check browser developer tools for CSS loading errors
|
||||
- Verify CSS file exists and is accessible
|
||||
- Clear browser cache and hard reload
|
||||
- Check for console errors
|
||||
|
||||
### Getting Help
|
||||
|
||||
- Check the application logs
|
||||
|
||||
@ -9,6 +9,9 @@ RUN apt-get update \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
gettext \
|
||||
curl \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
|
||||
&& apt-get install -y nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
208
README.md
208
README.md
@ -1,6 +1,6 @@
|
||||
# Django Boilerplate
|
||||
# Django Template
|
||||
|
||||
A production-ready Django boilerplate with built-in authentication, social login, role-based permissions, and Docker support.
|
||||
A production-ready Django template with built-in authentication, social login, role-based permissions, modern UI with Tailwind CSS, and Docker support.
|
||||
|
||||
## ✨ Features
|
||||
|
||||
@ -28,10 +28,13 @@ A production-ready Django boilerplate with built-in authentication, social login
|
||||
- Nginx reverse proxy
|
||||
- Gunicorn WSGI server
|
||||
|
||||
- 🎨 **Modern Frontend**
|
||||
- Bootstrap 5 integration
|
||||
- Responsive design
|
||||
- Clean, professional UI
|
||||
- 🎨 **Modern Frontend with Tailwind CSS**
|
||||
- Tailwind CSS v3.4+ integration with django-tailwind
|
||||
- Hot-reloading during development
|
||||
- Responsive design with mobile-first approach
|
||||
- Professional black/white theme
|
||||
- Modern card layouts and components
|
||||
- Optimized CSS builds for production
|
||||
|
||||
- ⚙️ **Environment Management**
|
||||
- Separate settings for development/production
|
||||
@ -121,10 +124,73 @@ docker-compose exec web python manage.py createsuperuser
|
||||
docker-compose exec web python manage.py create_superuser --email admin@example.com --password admin123
|
||||
```
|
||||
|
||||
### 7. Access the Application
|
||||
### 7. Start Tailwind Development Server
|
||||
|
||||
- **Web Application**: http://localhost:8000
|
||||
- **Django Admin**: http://localhost:8000/admin/
|
||||
```bash
|
||||
# In a separate terminal, start Tailwind's watch mode for hot reloading
|
||||
docker-compose exec web python manage.py tailwind start
|
||||
```
|
||||
|
||||
### 8. Access the Application
|
||||
|
||||
- **Web Application**: http://localhost:8001 (or http://localhost:8000)
|
||||
- **Django Admin**: http://localhost:8001/admin/
|
||||
|
||||
## 🎨 Tailwind CSS Development
|
||||
|
||||
### Hot Reloading Setup
|
||||
|
||||
The project uses `django-tailwind` for seamless Tailwind CSS integration:
|
||||
|
||||
1. **Development Mode:**
|
||||
```bash
|
||||
# Start Tailwind watch mode (automatically rebuilds CSS on changes)
|
||||
docker-compose exec web python manage.py tailwind start
|
||||
```
|
||||
|
||||
2. **Building for Production:**
|
||||
```bash
|
||||
# Build minified CSS for production
|
||||
docker-compose exec web python manage.py tailwind build
|
||||
```
|
||||
|
||||
3. **Customizing Styles:**
|
||||
- Edit templates with Tailwind utility classes
|
||||
- Modify `theme/static_src/src/styles.css` for custom CSS
|
||||
- Update `theme/static_src/tailwind.config.js` for configuration
|
||||
|
||||
### Theme Structure
|
||||
|
||||
```
|
||||
theme/
|
||||
├── static_src/ # Tailwind source files
|
||||
│ ├── src/
|
||||
│ │ └── styles.css # Main Tailwind CSS file
|
||||
│ ├── tailwind.config.js # Tailwind configuration
|
||||
│ ├── package.json # Node.js dependencies
|
||||
│ └── node_modules/ # Node.js packages
|
||||
├── static/
|
||||
│ └── css/
|
||||
│ └── dist/
|
||||
│ └── styles.css # Generated CSS file
|
||||
└── templates/ # Theme templates
|
||||
```
|
||||
|
||||
### Adding Custom Components
|
||||
|
||||
Create reusable Tailwind components in your templates:
|
||||
|
||||
```html
|
||||
<!-- Card component example -->
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200">
|
||||
<h2 class="text-xl font-semibold text-gray-900">Card Title</h2>
|
||||
</div>
|
||||
<div class="px-6 py-6">
|
||||
<!-- Card content -->
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 🔧 Development Setup
|
||||
|
||||
@ -159,6 +225,117 @@ docker-compose exec web python manage.py create_superuser --email admin@example.
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
## 🗄️ Third-Party Database Services
|
||||
|
||||
The application supports external PostgreSQL services like Neon, Supabase, Railway, and others. You can use either individual environment variables or a single DATABASE_URL.
|
||||
|
||||
### Supported Services
|
||||
|
||||
- **[Neon](https://neon.tech)** - Serverless PostgreSQL with branching
|
||||
- **[Supabase](https://supabase.com)** - Open source Firebase alternative
|
||||
- **[Railway](https://railway.app)** - Deploy from GitHub in seconds
|
||||
- **[ElephantSQL](https://www.elephantsql.com)** - PostgreSQL as a Service
|
||||
- **[Amazon RDS](https://aws.amazon.com/rds)** - AWS managed databases
|
||||
- **[Google Cloud SQL](https://cloud.google.com/sql)** - Google Cloud databases
|
||||
- **Any PostgreSQL-compatible service**
|
||||
|
||||
### Configuration Methods
|
||||
|
||||
#### Method 1: DATABASE_URL (Recommended)
|
||||
|
||||
Set a single environment variable:
|
||||
|
||||
```env
|
||||
DATABASE_URL=postgresql://user:password@host:port/database?sslmode=require
|
||||
```
|
||||
|
||||
**Neon Example:**
|
||||
```env
|
||||
DATABASE_URL=postgresql://neondb_owner:npg_ZO9W1DxrTwJu@ep-solitary-water-a1ucgv2p-pooler.ap-southeast-1.aws.neon.tech/neondb?sslmode=require&channel_binding=require
|
||||
```
|
||||
|
||||
**Supabase Example:**
|
||||
```env
|
||||
DATABASE_URL=postgresql://postgres:your-password@db.xxx.supabase.co:5432/postgres?sslmode=require
|
||||
```
|
||||
|
||||
#### Method 2: Individual Variables
|
||||
|
||||
For more control, use separate environment variables:
|
||||
|
||||
```env
|
||||
DB_NAME=your_database_name
|
||||
DB_USER=your_username
|
||||
DB_PASSWORD=your_password
|
||||
DB_HOST=your-host.amazonaws.com
|
||||
DB_PORT=5432
|
||||
DB_SSLMODE=require # For secure connections
|
||||
```
|
||||
|
||||
### Quick Setup Examples
|
||||
|
||||
#### Neon Database
|
||||
|
||||
1. **Create a Neon project** at [neon.tech](https://neon.tech)
|
||||
2. **Copy your connection string** from the Neon dashboard
|
||||
3. **Add to your .env file:**
|
||||
```env
|
||||
DATABASE_URL=postgresql://user:pass@ep-xxx.us-east-1.aws.neon.tech/dbname?sslmode=require
|
||||
```
|
||||
|
||||
#### Supabase Database
|
||||
|
||||
1. **Create a Supabase project** at [supabase.com](https://supabase.com)
|
||||
2. **Go to Settings > Database**
|
||||
3. **Copy the connection string and add to .env:**
|
||||
```env
|
||||
DATABASE_URL=postgresql://postgres:your-password@db.xxx.supabase.co:5432/postgres?sslmode=require
|
||||
```
|
||||
|
||||
#### Railway Database
|
||||
|
||||
1. **Deploy to Railway** from GitHub
|
||||
2. **Add PostgreSQL plugin**
|
||||
3. **Railway automatically sets DATABASE_URL**
|
||||
|
||||
### SSL and Security
|
||||
|
||||
For production databases, always use SSL:
|
||||
|
||||
```env
|
||||
# Enable SSL for external databases
|
||||
DB_SSLMODE=require # or 'prefer' for flexible connections
|
||||
DATABASE_URL=postgresql://user:pass@host/db?sslmode=require
|
||||
```
|
||||
|
||||
### Migration Commands
|
||||
|
||||
After configuring your external database:
|
||||
|
||||
```bash
|
||||
# Run migrations
|
||||
python manage.py migrate
|
||||
|
||||
# Create user groups
|
||||
python manage.py create_groups
|
||||
|
||||
# Create admin user
|
||||
python manage.py createsuperuser
|
||||
```
|
||||
|
||||
### Docker with External Database
|
||||
|
||||
When using external databases with Docker, update your docker-compose.yml:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
# ... other config
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://user:pass@external-host/db?sslmode=require
|
||||
# Remove the 'db' service when using external database
|
||||
```
|
||||
|
||||
## 🌐 Social Authentication Setup
|
||||
|
||||
### Google OAuth2
|
||||
@ -252,6 +429,13 @@ django-template/
|
||||
│ └── core/ # Core application logic
|
||||
├── templates/ # HTML templates
|
||||
├── static/ # Static files (CSS, JS, images)
|
||||
├── theme/ # Tailwind CSS theme
|
||||
│ ├── static_src/ # Tailwind source files
|
||||
│ │ ├── src/ # CSS source files
|
||||
│ │ ├── tailwind.config.js
|
||||
│ │ └── package.json # Node.js dependencies
|
||||
│ ├── static/ # Generated CSS files
|
||||
│ └── templates/ # Theme-specific templates
|
||||
├── requirements/ # Python dependencies
|
||||
├── Dockerfile # Docker configuration
|
||||
├── docker-compose.yml # Development Docker Compose
|
||||
@ -301,6 +485,12 @@ python manage.py create_groups
|
||||
# Create superuser with admin role
|
||||
python manage.py create_superuser --email admin@example.com --password admin123
|
||||
|
||||
# Tailwind CSS commands
|
||||
python manage.py tailwind install # Install Tailwind CSS dependencies
|
||||
python manage.py tailwind start # Start development server with hot reload
|
||||
python manage.py tailwind build # Build production CSS
|
||||
python manage.py tailwind check # Check for Tailwind updates
|
||||
|
||||
# Standard Django commands
|
||||
python manage.py migrate
|
||||
python manage.py collectstatic
|
||||
|
||||
@ -29,11 +29,14 @@ THIRD_PARTY_APPS = [
|
||||
'allauth.socialaccount',
|
||||
'allauth.socialaccount.providers.google',
|
||||
'whitenoise.runserver_nostatic',
|
||||
'tailwind',
|
||||
'django_browser_reload',
|
||||
]
|
||||
|
||||
LOCAL_APPS = [
|
||||
'apps.accounts',
|
||||
'apps.core',
|
||||
'theme',
|
||||
]
|
||||
|
||||
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
||||
@ -70,16 +73,35 @@ TEMPLATES = [
|
||||
|
||||
WSGI_APPLICATION = 'django_project.wsgi.application'
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': config('DB_NAME', default='django_db'),
|
||||
'USER': config('DB_USER', default='django_user'),
|
||||
'PASSWORD': config('DB_PASSWORD', default='django_password'),
|
||||
'HOST': config('DB_HOST', default='localhost'),
|
||||
'PORT': config('DB_PORT', default='5432'),
|
||||
import dj_database_url
|
||||
|
||||
# Database configuration with support for DATABASE_URL
|
||||
DATABASE_URL = config('DATABASE_URL', default=None)
|
||||
|
||||
if DATABASE_URL:
|
||||
# Use DATABASE_URL if provided (common for external services like Neon, Heroku, etc.)
|
||||
DATABASES = {
|
||||
'default': dj_database_url.config(
|
||||
default=DATABASE_URL,
|
||||
conn_max_age=600,
|
||||
conn_health_checks=True,
|
||||
)
|
||||
}
|
||||
else:
|
||||
# Use individual environment variables (for Docker Compose and local development)
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': config('DB_NAME', default='django_db'),
|
||||
'USER': config('DB_USER', default='django_user'),
|
||||
'PASSWORD': config('DB_PASSWORD', default='django_password'),
|
||||
'HOST': config('DB_HOST', default='localhost'),
|
||||
'PORT': config('DB_PORT', default='5432'),
|
||||
'OPTIONS': {
|
||||
'sslmode': config('DB_SSLMODE', default='prefer'),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
@ -156,4 +178,10 @@ SOCIALACCOUNT_PROVIDERS = {
|
||||
}
|
||||
}
|
||||
|
||||
SOCIALACCOUNT_LOGIN_ON_GET = True
|
||||
SOCIALACCOUNT_LOGIN_ON_GET = True
|
||||
|
||||
# Tailwind CSS Configuration
|
||||
TAILWIND_APP_NAME = 'theme'
|
||||
|
||||
# Production static files configuration
|
||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||
@ -7,6 +7,9 @@ DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0']
|
||||
|
||||
# Add browser reload middleware for development
|
||||
MIDDLEWARE.insert(0, 'django_browser_reload.middleware.BrowserReloadMiddleware')
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
|
||||
@ -13,4 +13,5 @@ urlpatterns = [
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
urlpatterns += [path("__reload__/", include("django_browser_reload.urls"))]
|
||||
@ -4,4 +4,6 @@ python-decouple==3.8
|
||||
psycopg2-binary==2.9.7
|
||||
Pillow==10.0.1
|
||||
whitenoise==6.6.0
|
||||
gunicorn==21.2.0
|
||||
gunicorn==21.2.0
|
||||
django-tailwind[reload]==3.8.0
|
||||
dj-database-url==2.1.0
|
||||
@ -1,22 +1,22 @@
|
||||
// Custom JavaScript for Django Boilerplate
|
||||
// Custom JavaScript for Application
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Auto-dismiss alerts after 5 seconds
|
||||
setTimeout(function() {
|
||||
const alerts = document.querySelectorAll('.alert');
|
||||
alerts.forEach(function(alert) {
|
||||
const bsAlert = new bootstrap.Alert(alert);
|
||||
bsAlert.close();
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
// Add smooth scrolling to anchor links
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
document.querySelector(this.getAttribute('href')).scrollIntoView({
|
||||
behavior: 'smooth'
|
||||
});
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Mobile menu toggle function
|
||||
function toggleMobileMenu() {
|
||||
const mobileMenu = document.getElementById('mobileMenu');
|
||||
mobileMenu.classList.toggle('hidden');
|
||||
}
|
||||
@ -1,88 +1,100 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Dashboard - Django Boilerplate{% endblock %}
|
||||
{% block title %}Dashboard{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>Welcome to Your Dashboard</h1>
|
||||
<p class="lead">Hello, <strong>{{ user.full_name|default:user.email }}</strong>!</p>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold text-gray-900 mb-2">Welcome to Your Dashboard</h1>
|
||||
<p class="text-lg text-gray-600">Hello, <strong class="text-gray-900">{{ user.full_name|default:user.email }}</strong>!</p>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Account Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Email:</strong> {{ user.email }}</p>
|
||||
<p><strong>Name:</strong> {{ user.full_name|default:"Not set" }}</p>
|
||||
<p><strong>Username:</strong> {{ user.username }}</p>
|
||||
<p><strong>Member since:</strong> {{ user.date_joined|date:"M d, Y" }}</p>
|
||||
<p><strong>Email verified:</strong>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200">
|
||||
<h2 class="text-xl font-semibold text-gray-900">Account Information</h2>
|
||||
</div>
|
||||
<div class="px-6 py-6">
|
||||
<div class="space-y-4">
|
||||
<p class="text-gray-700"><strong class="text-gray-900">Email:</strong> {{ user.email }}</p>
|
||||
<p class="text-gray-700"><strong class="text-gray-900">Name:</strong> {{ user.full_name|default:"Not set" }}</p>
|
||||
<p class="text-gray-700"><strong class="text-gray-900">Username:</strong> {{ user.username }}</p>
|
||||
<p class="text-gray-700"><strong class="text-gray-900">Member since:</strong> {{ user.date_joined|date:"M d, Y" }}</p>
|
||||
<p class="text-gray-700">
|
||||
<strong class="text-gray-900">Email verified:</strong>
|
||||
{% if user.is_verified %}
|
||||
<span class="badge bg-success">Yes</span>
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">Yes</span>
|
||||
{% else %}
|
||||
<span class="badge bg-warning">No</span>
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">No</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
<a href="{% url 'accounts:profile_edit' %}" class="btn btn-primary">Edit Profile</a>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<a href="{% url 'accounts:profile_edit' %}" class="bg-black text-white px-4 py-2 rounded-md hover:bg-gray-800 transition-colors duration-200 inline-flex items-center">
|
||||
Edit Profile
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Your Roles</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200">
|
||||
<h2 class="text-xl font-semibold text-gray-900">Your Roles</h2>
|
||||
</div>
|
||||
<div class="px-6 py-6">
|
||||
<div class="mb-4">
|
||||
{% if user_groups %}
|
||||
{% for group in user_groups %}
|
||||
<span class="badge bg-secondary me-1">{{ group.name|title }}</span>
|
||||
{% endfor %}
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{% for group in user_groups %}
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800">{{ group.name|title }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted">No roles assigned</p>
|
||||
<p class="text-gray-500">No roles assigned</p>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
|
||||
<h6>Access Levels:</h6>
|
||||
<ul class="list-unstyled">
|
||||
<li>
|
||||
<i class="text-success">✓</i> User Dashboard
|
||||
</div>
|
||||
|
||||
<hr class="my-4 border-gray-200">
|
||||
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-gray-900 mb-3">Access Levels:</h3>
|
||||
<ul class="space-y-2">
|
||||
<li class="flex items-center text-sm">
|
||||
<span class="text-green-500 mr-2">✓</span>
|
||||
<span class="text-gray-700">User Dashboard</span>
|
||||
</li>
|
||||
{% if user.groups.all %}
|
||||
{% for group in user.groups.all %}
|
||||
{% if group.name == 'staff' or group.name == 'admin' %}
|
||||
<li>
|
||||
<i class="text-success">✓</i>
|
||||
<a href="{% url 'core:staff_dashboard' %}">Staff Dashboard</a>
|
||||
<li class="flex items-center text-sm">
|
||||
<span class="text-green-500 mr-2">✓</span>
|
||||
<a href="{% url 'core:staff_dashboard' %}" class="text-gray-700 hover:text-black transition-colors duration-200">Staff Dashboard</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if group.name == 'admin' %}
|
||||
<li>
|
||||
<i class="text-success">✓</i>
|
||||
<a href="{% url 'core:admin_dashboard' %}">Admin Dashboard</a>
|
||||
<li class="flex items-center text-sm">
|
||||
<span class="text-green-500 mr-2">✓</span>
|
||||
<a href="{% url 'core:admin_dashboard' %}" class="text-gray-700 hover:text-black transition-colors duration-200">Admin Dashboard</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if not user.groups.filter|length %}
|
||||
<li>
|
||||
<i class="text-muted">✗</i> Staff Dashboard
|
||||
<li class="flex items-center text-sm">
|
||||
<span class="text-gray-400 mr-2">✗</span>
|
||||
<span class="text-gray-500">Staff Dashboard</span>
|
||||
</li>
|
||||
<li>
|
||||
<i class="text-muted">✗</i> Admin Dashboard
|
||||
<li class="flex items-center text-sm">
|
||||
<span class="text-gray-400 mr-2">✗</span>
|
||||
<span class="text-gray-500">Admin Dashboard</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<li>
|
||||
<i class="text-muted">✗</i> Staff Dashboard
|
||||
<li class="flex items-center text-sm">
|
||||
<span class="text-gray-400 mr-2">✗</span>
|
||||
<span class="text-gray-500">Staff Dashboard</span>
|
||||
</li>
|
||||
<li>
|
||||
<i class="text-muted">✗</i> Admin Dashboard
|
||||
<li class="flex items-center text-sm">
|
||||
<span class="text-gray-400 mr-2">✗</span>
|
||||
<span class="text-gray-500">Admin Dashboard</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
@ -1,67 +1,90 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Profile - Django Boilerplate{% endblock %}
|
||||
{% block title %}Profile{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5>Your Profile</h5>
|
||||
<a href="{% url 'accounts:profile_edit' %}" class="btn btn-primary btn-sm">Edit Profile</a>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div class="lg:col-span-2">
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
|
||||
<h2 class="text-xl font-semibold text-gray-900">Your Profile</h2>
|
||||
<a href="{% url 'accounts:profile_edit' %}" class="bg-black text-white px-3 py-1.5 text-sm rounded-md hover:bg-gray-800 transition-colors duration-200">
|
||||
Edit Profile
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4 text-center">
|
||||
<div class="px-6 py-6">
|
||||
<div class="flex flex-col md:flex-row gap-6">
|
||||
<div class="flex-shrink-0 text-center">
|
||||
{% if user.profile.avatar %}
|
||||
<img src="{{ user.profile.avatar.url }}" class="img-thumbnail" width="150" height="150">
|
||||
<img src="{{ user.profile.avatar.url }}" class="w-32 h-32 rounded-full mx-auto border border-gray-200 object-cover" alt="Profile Avatar">
|
||||
{% else %}
|
||||
<div class="bg-secondary d-flex align-items-center justify-content-center" style="width: 150px; height: 150px;">
|
||||
<i class="text-white fs-1">👤</i>
|
||||
<div class="w-32 h-32 rounded-full bg-gray-100 flex items-center justify-content-center mx-auto border border-gray-200">
|
||||
<span class="text-4xl text-gray-500">👤</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<h4>{{ user.full_name|default:user.email }}</h4>
|
||||
<p class="text-muted">{{ user.email }}</p>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-2xl font-bold text-gray-900 mb-1">{{ user.full_name|default:user.email }}</h3>
|
||||
<p class="text-gray-600 mb-4">{{ user.email }}</p>
|
||||
|
||||
{% if user.profile.bio %}
|
||||
<p><strong>Bio:</strong> {{ user.profile.bio }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if user.profile.location %}
|
||||
<p><strong>Location:</strong> {{ user.profile.location }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if user.profile.birth_date %}
|
||||
<p><strong>Birth Date:</strong> {{ user.profile.birth_date }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if user.profile.phone_number %}
|
||||
<p><strong>Phone:</strong> {{ user.profile.phone_number }}</p>
|
||||
{% endif %}
|
||||
|
||||
<p><strong>Member since:</strong> {{ user.date_joined|date:"M d, Y" }}</p>
|
||||
<div class="space-y-3">
|
||||
{% if user.profile.bio %}
|
||||
<div>
|
||||
<span class="text-sm font-medium text-gray-900">Bio:</span>
|
||||
<p class="text-gray-700 mt-1">{{ user.profile.bio }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if user.profile.location %}
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Location:</span> {{ user.profile.location }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if user.profile.birth_date %}
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Birth Date:</span> {{ user.profile.birth_date }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if user.profile.phone_number %}
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Phone:</span> {{ user.profile.phone_number }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Member since:</span> {{ user.date_joined|date:"M d, Y" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Account Status</h5>
|
||||
<div class="lg:col-span-1">
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200">
|
||||
<h2 class="text-xl font-semibold text-gray-900">Account Status</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Email verified:</strong>
|
||||
{% if user.is_verified %}
|
||||
<span class="badge bg-success">Yes</span>
|
||||
{% else %}
|
||||
<span class="badge bg-warning">No</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p><strong>Account type:</strong> {{ user.groups.first.name|default:"User"|title }}</p>
|
||||
<div class="px-6 py-6">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<span class="text-sm font-medium text-gray-900">Email verified:</span>
|
||||
<div class="mt-1">
|
||||
{% if user.is_verified %}
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">Verified</span>
|
||||
{% else %}
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">Unverified</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-sm font-medium text-gray-900">Account type:</span>
|
||||
<p class="text-gray-700 mt-1">{{ user.groups.first.name|default:"User"|title }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,24 +1,76 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Edit Profile - Django Boilerplate{% endblock %}
|
||||
{% block title %}Edit Profile{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Edit Your Profile</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="{% url 'accounts:profile' %}" class="btn btn-secondary">Cancel</a>
|
||||
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200">
|
||||
<h2 class="text-xl font-semibold text-gray-900">Edit Your Profile</h2>
|
||||
</div>
|
||||
<div class="px-6 py-6">
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-6">
|
||||
{% csrf_token %}
|
||||
|
||||
{% for field in form %}
|
||||
<div>
|
||||
<label for="{{ field.id_for_label }}" class="block text-sm font-medium text-gray-900 mb-1">
|
||||
{{ field.label }}
|
||||
</label>
|
||||
|
||||
{% if field.field.widget.input_type == 'file' %}
|
||||
<input type="file"
|
||||
name="{{ field.name }}"
|
||||
id="{{ field.id_for_label }}"
|
||||
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-gray-50 file:text-gray-700 hover:file:bg-gray-100"
|
||||
{% if field.field.required %}required{% endif %}>
|
||||
{% elif field.field.widget.input_type == 'textarea' %}
|
||||
<textarea name="{{ field.name }}"
|
||||
id="{{ field.id_for_label }}"
|
||||
rows="4"
|
||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-black focus:border-black"
|
||||
{% if field.field.required %}required{% endif %}
|
||||
placeholder="{{ field.field.widget.attrs.placeholder|default:'' }}">{{ field.value|default:'' }}</textarea>
|
||||
{% elif field.field.widget.input_type == 'date' %}
|
||||
<input type="date"
|
||||
name="{{ field.name }}"
|
||||
id="{{ field.id_for_label }}"
|
||||
value="{{ field.value|default:'' }}"
|
||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-black focus:border-black"
|
||||
{% if field.field.required %}required{% endif %}>
|
||||
{% else %}
|
||||
<input type="{{ field.field.widget.input_type|default:'text' }}"
|
||||
name="{{ field.name }}"
|
||||
id="{{ field.id_for_label }}"
|
||||
value="{{ field.value|default:'' }}"
|
||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-black focus:border-black"
|
||||
{% if field.field.required %}required{% endif %}
|
||||
placeholder="{{ field.field.widget.attrs.placeholder|default:'' }}">
|
||||
{% endif %}
|
||||
|
||||
{% if field.help_text %}
|
||||
<p class="mt-1 text-sm text-gray-500">{{ field.help_text }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if field.errors %}
|
||||
{% for error in field.errors %}
|
||||
<p class="mt-1 text-sm text-red-600">{{ error }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="flex justify-between pt-4">
|
||||
<a href="{% url 'accounts:profile' %}"
|
||||
class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors duration-200">
|
||||
Cancel
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="bg-black text-white px-6 py-2 rounded-md hover:bg-gray-800 transition-colors duration-200">
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,67 +1,91 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Admin Dashboard - Django Boilerplate{% endblock %}
|
||||
{% block title %}Admin Dashboard{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>🔐 Admin Dashboard</h1>
|
||||
<p class="lead">Administrative control panel</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">User Management</h5>
|
||||
<p class="card-text">Manage user accounts, roles, and permissions</p>
|
||||
<a href="/admin/accounts/user/" class="btn btn-primary">Manage Users</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">Group Management</h5>
|
||||
<p class="card-text">Configure user groups and permissions</p>
|
||||
<a href="/admin/auth/group/" class="btn btn-primary">Manage Groups</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">Site Administration</h5>
|
||||
<p class="card-text">Access full Django admin interface</p>
|
||||
<a href="/admin/" class="btn btn-primary">Django Admin</a>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="text-4xl mr-3">🔐</span>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-gray-900">Admin Dashboard</h1>
|
||||
<p class="text-lg text-gray-600">Administrative control panel</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>System Information</h5>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200 hover:shadow-xl transition-shadow duration-200">
|
||||
<div class="px-6 py-8 text-center">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">User Management</h3>
|
||||
<p class="text-gray-600 mb-6">Manage user accounts, roles, and permissions</p>
|
||||
<a href="/admin/accounts/user/" class="bg-black text-white px-6 py-2 rounded-md hover:bg-gray-800 transition-colors duration-200 inline-block">
|
||||
Manage Users
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200 hover:shadow-xl transition-shadow duration-200">
|
||||
<div class="px-6 py-8 text-center">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">Group Management</h3>
|
||||
<p class="text-gray-600 mb-6">Configure user groups and permissions</p>
|
||||
<a href="/admin/auth/group/" class="bg-black text-white px-6 py-2 rounded-md hover:bg-gray-800 transition-colors duration-200 inline-block">
|
||||
Manage Groups
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200 hover:shadow-xl transition-shadow duration-200">
|
||||
<div class="px-6 py-8 text-center">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">Site Administration</h3>
|
||||
<p class="text-gray-600 mb-6">Access full Django admin interface</p>
|
||||
<a href="/admin/" class="bg-black text-white px-6 py-2 rounded-md hover:bg-gray-800 transition-colors duration-200 inline-block">
|
||||
Django Admin
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200">
|
||||
<h2 class="text-xl font-semibold text-gray-900">System Information</h2>
|
||||
</div>
|
||||
<div class="px-6 py-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Current User</h3>
|
||||
<div class="space-y-3">
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Name:</span> {{ user.full_name|default:user.email }}
|
||||
</p>
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Role:</span> Administrator
|
||||
</p>
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Last Login:</span> {{ user.last_login|date:"M d, Y H:i" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6>Current User</h6>
|
||||
<p><strong>Name:</strong> {{ user.full_name|default:user.email }}</p>
|
||||
<p><strong>Role:</strong> Administrator</p>
|
||||
<p><strong>Last Login:</strong> {{ user.last_login|date:"M d, Y H:i" }}</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6>Quick Stats</h6>
|
||||
<p><strong>Total Users:</strong> <span class="badge bg-info">{{ users_count|default:"N/A" }}</span></p>
|
||||
<p><strong>Active Sessions:</strong> <span class="badge bg-success">{{ active_sessions|default:"N/A" }}</span></p>
|
||||
<p><strong>System Status:</strong> <span class="badge bg-success">Online</span></p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Quick Stats</h3>
|
||||
<div class="space-y-3">
|
||||
<p class="text-gray-700 flex justify-between">
|
||||
<span class="font-medium text-gray-900">Total Users:</span>
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||||
{{ users_count|default:"N/A" }}
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-gray-700 flex justify-between">
|
||||
<span class="font-medium text-gray-900">Active Sessions:</span>
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||||
{{ active_sessions|default:"N/A" }}
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-gray-700 flex justify-between">
|
||||
<span class="font-medium text-gray-900">System Status:</span>
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||||
Online
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,80 +1,107 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" class="h-full">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Application{% endblock %}</title>
|
||||
{% load static %}
|
||||
{% load tailwind_tags %}
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
{% tailwind_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{% url 'core:home' %}">App</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'core:home' %}">Home</a>
|
||||
</li>
|
||||
<body class="h-full flex flex-col">
|
||||
<nav class="bg-black shadow-lg">
|
||||
<div class="max-w-7xl mx-auto px-4">
|
||||
<div class="flex justify-between h-16">
|
||||
<div class="flex items-center">
|
||||
<a class="text-white text-xl font-semibold" href="{% url 'core:home' %}">App</a>
|
||||
|
||||
<div class="hidden md:flex items-center ml-10 space-x-8">
|
||||
<a class="text-gray-300 hover:text-white px-3 py-2 text-sm font-medium" href="{% url 'core:home' %}">Home</a>
|
||||
{% if user.is_authenticated %}
|
||||
<a class="text-gray-300 hover:text-white px-3 py-2 text-sm font-medium" href="{% url 'accounts:dashboard' %}">Dashboard</a>
|
||||
{% if user.groups.all %}
|
||||
{% for group in user.groups.all %}
|
||||
{% if group.name == 'staff' or group.name == 'admin' %}
|
||||
<a class="text-gray-300 hover:text-white px-3 py-2 text-sm font-medium" href="{% url 'core:staff_dashboard' %}">Staff</a>
|
||||
{% endif %}
|
||||
{% if group.name == 'admin' %}
|
||||
<a class="text-gray-300 hover:text-white px-3 py-2 text-sm font-medium" href="{% url 'core:admin_dashboard' %}">Admin</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden md:flex items-center space-x-4">
|
||||
{% if user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'accounts:dashboard' %}">Dashboard</a>
|
||||
</li>
|
||||
<div class="relative group">
|
||||
<button class="text-gray-300 hover:text-white px-3 py-2 text-sm font-medium">
|
||||
{{ user.full_name|default:user.email }}
|
||||
</button>
|
||||
<div class="absolute right-0 w-48 mt-2 py-2 bg-white rounded-lg shadow-xl opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-300">
|
||||
<a class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" href="{% url 'accounts:profile' %}">Profile</a>
|
||||
<hr class="my-1">
|
||||
<a class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" href="{% url 'account_logout' %}">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<a class="text-gray-300 hover:text-white px-3 py-2 text-sm font-medium" href="{% url 'account_login' %}">Login</a>
|
||||
<a class="bg-white text-black px-4 py-2 rounded-md text-sm font-medium hover:bg-gray-100" href="{% url 'account_signup' %}">Sign Up</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Mobile menu button -->
|
||||
<div class="md:hidden flex items-center">
|
||||
<button class="text-gray-300 hover:text-white" onclick="toggleMobileMenu()">
|
||||
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile menu -->
|
||||
<div id="mobileMenu" class="md:hidden hidden">
|
||||
<div class="px-2 pt-2 pb-3 space-y-1">
|
||||
<a class="text-gray-300 hover:text-white block px-3 py-2 text-base font-medium" href="{% url 'core:home' %}">Home</a>
|
||||
{% if user.is_authenticated %}
|
||||
<a class="text-gray-300 hover:text-white block px-3 py-2 text-base font-medium" href="{% url 'accounts:dashboard' %}">Dashboard</a>
|
||||
{% if user.groups.all %}
|
||||
{% for group in user.groups.all %}
|
||||
{% if group.name == 'staff' or group.name == 'admin' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'core:staff_dashboard' %}">Staff</a>
|
||||
</li>
|
||||
<a class="text-gray-300 hover:text-white block px-3 py-2 text-base font-medium" href="{% url 'core:staff_dashboard' %}">Staff</a>
|
||||
{% endif %}
|
||||
{% if group.name == 'admin' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'core:admin_dashboard' %}">Admin</a>
|
||||
</li>
|
||||
<a class="text-gray-300 hover:text-white block px-3 py-2 text-base font-medium" href="{% url 'core:admin_dashboard' %}">Admin</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav">
|
||||
{% if user.is_authenticated %}
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
|
||||
{{ user.full_name|default:user.email }}
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="{% url 'accounts:profile' %}">Profile</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="{% url 'account_logout' %}">Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<a class="text-gray-300 hover:text-white block px-3 py-2 text-base font-medium" href="{% url 'accounts:profile' %}">Profile</a>
|
||||
<a class="text-gray-300 hover:text-white block px-3 py-2 text-base font-medium" href="{% url 'account_logout' %}">Logout</a>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'account_login' %}">Login</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'account_signup' %}">Sign Up</a>
|
||||
</li>
|
||||
<a class="text-gray-300 hover:text-white block px-3 py-2 text-base font-medium" href="{% url 'account_login' %}">Login</a>
|
||||
<a class="text-gray-300 hover:text-white block px-3 py-2 text-base font-medium" href="{% url 'account_signup' %}">Sign Up</a>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container mt-4">
|
||||
<main class="flex-1 max-w-7xl mx-auto px-4 py-8 w-full">
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
<div class="mb-4 p-4 rounded-lg {% if message.tags == 'error' %}bg-red-100 text-red-700 border border-red-200{% elif message.tags == 'success' %}bg-green-100 text-green-700 border border-green-200{% elif message.tags == 'warning' %}bg-yellow-100 text-yellow-700 border border-yellow-200{% else %}bg-blue-100 text-blue-700 border border-blue-200{% endif %}" role="alert">
|
||||
<div class="flex justify-between items-center">
|
||||
<span>{{ message }}</span>
|
||||
<button type="button" class="text-gray-400 hover:text-gray-600" onclick="this.parentElement.parentElement.remove()">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
@ -83,13 +110,12 @@
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="bg-dark text-light text-center py-3 mt-5">
|
||||
<div class="container">
|
||||
<p>© 2024 Django Boilerplate. Built with Django & Bootstrap.</p>
|
||||
<footer class="bg-black text-white text-center py-6 mt-auto">
|
||||
<div class="max-w-7xl mx-auto px-4">
|
||||
<p class="text-sm text-gray-400">© 2024 Your Application. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="{% static 'js/main.js' %}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -3,66 +3,72 @@
|
||||
{% block title %}Home{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-8 mx-auto">
|
||||
<div class="jumbotron bg-light p-5 rounded">
|
||||
<h1 class="display-4">Welcome</h1>
|
||||
<p class="lead">
|
||||
A modern web application with secure authentication,
|
||||
role-based permissions, and powerful features.
|
||||
</p>
|
||||
<hr class="my-4">
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<p>Hello, <strong>{{ user.full_name|default:user.email }}</strong>!</p>
|
||||
<a class="btn btn-primary btn-lg" href="{% url 'accounts:dashboard' %}" role="button">
|
||||
Go to Dashboard
|
||||
</a>
|
||||
{% else %}
|
||||
<p>Get started by creating an account or logging in.</p>
|
||||
<a class="btn btn-primary btn-lg me-3" href="{% url 'account_signup' %}" role="button">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="bg-gray-50 rounded-lg p-8 mb-12 text-center">
|
||||
<h1 class="text-5xl font-bold text-gray-900 mb-4">Welcome</h1>
|
||||
<p class="text-xl text-gray-600 mb-6 max-w-2xl mx-auto">
|
||||
A modern web application with secure authentication,
|
||||
role-based permissions, and powerful features.
|
||||
</p>
|
||||
<hr class="border-gray-300 my-6 w-24 mx-auto">
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<p class="text-gray-700 mb-6">Hello, <strong class="text-gray-900">{{ user.full_name|default:user.email }}</strong>!</p>
|
||||
<a href="{% url 'accounts:dashboard' %}"
|
||||
class="bg-black text-white px-8 py-3 rounded-md hover:bg-gray-800 transition-colors duration-200 text-lg font-medium inline-block">
|
||||
Go to Dashboard
|
||||
</a>
|
||||
{% else %}
|
||||
<p class="text-gray-700 mb-6">Get started by creating an account or logging in.</p>
|
||||
<div class="space-x-4">
|
||||
<a href="{% url 'account_signup' %}"
|
||||
class="bg-black text-white px-8 py-3 rounded-md hover:bg-gray-800 transition-colors duration-200 text-lg font-medium inline-block">
|
||||
Sign Up
|
||||
</a>
|
||||
<a class="btn btn-outline-primary btn-lg" href="{% url 'account_login' %}" role="button">
|
||||
<a href="{% url 'account_login' %}"
|
||||
class="border-2 border-gray-900 text-gray-900 px-8 py-3 rounded-md hover:bg-gray-900 hover:text-white transition-colors duration-200 text-lg font-medium inline-block">
|
||||
Login
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">🔐 Authentication</h5>
|
||||
<p class="card-text">
|
||||
Complete authentication system with email verification,
|
||||
password reset, and social login (Google & Facebook).
|
||||
</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200 h-full">
|
||||
<div class="p-6">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="text-2xl mr-3">🔐</span>
|
||||
<h3 class="text-xl font-semibold text-gray-900">Authentication</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 leading-relaxed">
|
||||
Complete authentication system with email verification,
|
||||
password reset, and social login (Google & Facebook).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">👥 Role-Based Access</h5>
|
||||
<p class="card-text">
|
||||
Built-in user group system with admin, staff, and user roles
|
||||
for granular permission control.
|
||||
</p>
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200 h-full">
|
||||
<div class="p-6">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="text-2xl mr-3">👥</span>
|
||||
<h3 class="text-xl font-semibold text-gray-900">Role-Based Access</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 leading-relaxed">
|
||||
Built-in user group system with admin, staff, and user roles
|
||||
for granular permission control.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">🐳 Docker Ready</h5>
|
||||
<p class="card-text">
|
||||
Fully containerized with Docker Compose, PostgreSQL database,
|
||||
and production-ready configuration.
|
||||
</p>
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200 h-full">
|
||||
<div class="p-6">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="text-2xl mr-3">🐳</span>
|
||||
<h3 class="text-xl font-semibold text-gray-900">Docker Ready</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 leading-relaxed">
|
||||
Fully containerized with Docker Compose, PostgreSQL database,
|
||||
and production-ready configuration.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,59 +1,72 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Staff Dashboard - Django Boilerplate{% endblock %}
|
||||
{% block title %}Staff Dashboard{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>👨💼 Staff Dashboard</h1>
|
||||
<p class="lead">Staff management panel</p>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center mb-4">
|
||||
<span class="text-4xl mr-3">👨💼</span>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-gray-900">Staff Dashboard</h1>
|
||||
<p class="text-lg text-gray-600">Staff management panel</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">User Support</h5>
|
||||
<p class="card-text">Assist users with account and technical issues</p>
|
||||
<a href="#" class="btn btn-primary">Support Center</a>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200 hover:shadow-xl transition-shadow duration-200">
|
||||
<div class="px-6 py-8 text-center">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">User Support</h3>
|
||||
<p class="text-gray-600 mb-6">Assist users with account and technical issues</p>
|
||||
<a href="#" class="bg-black text-white px-6 py-2 rounded-md hover:bg-gray-800 transition-colors duration-200 inline-block">
|
||||
Support Center
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">Content Management</h5>
|
||||
<p class="card-text">Manage and moderate platform content</p>
|
||||
<a href="#" class="btn btn-primary">Content Panel</a>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200 hover:shadow-xl transition-shadow duration-200">
|
||||
<div class="px-6 py-8 text-center">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">Content Management</h3>
|
||||
<p class="text-gray-600 mb-6">Manage and moderate platform content</p>
|
||||
<a href="#" class="bg-black text-white px-6 py-2 rounded-md hover:bg-gray-800 transition-colors duration-200 inline-block">
|
||||
Content Panel
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Staff Information</h5>
|
||||
<div class="bg-white rounded-lg shadow-lg border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200">
|
||||
<h2 class="text-xl font-semibold text-gray-900">Staff Information</h2>
|
||||
</div>
|
||||
<div class="px-6 py-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Current User</h3>
|
||||
<div class="space-y-3">
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Name:</span> {{ user.full_name|default:user.email }}
|
||||
</p>
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Role:</span> Staff Member
|
||||
</p>
|
||||
<p class="text-gray-700">
|
||||
<span class="font-medium text-gray-900">Department:</span> {{ user.profile.department|default:"General" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6>Current User</h6>
|
||||
<p><strong>Name:</strong> {{ user.full_name|default:user.email }}</p>
|
||||
<p><strong>Role:</strong> Staff Member</p>
|
||||
<p><strong>Department:</strong> {{ user.profile.department|default:"General" }}</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6>Quick Actions</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-outline-primary btn-sm">View Reports</button>
|
||||
<button class="btn btn-outline-secondary btn-sm">Export Data</button>
|
||||
<button class="btn btn-outline-info btn-sm">Send Notifications</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Quick Actions</h3>
|
||||
<div class="space-y-3">
|
||||
<button class="w-full px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors duration-200 text-left">
|
||||
View Reports
|
||||
</button>
|
||||
<button class="w-full px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors duration-200 text-left">
|
||||
Export Data
|
||||
</button>
|
||||
<button class="w-full px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors duration-200 text-left">
|
||||
Send Notifications
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
0
theme/__init__.py
Normal file
0
theme/__init__.py
Normal file
5
theme/apps.py
Normal file
5
theme/apps.py
Normal file
@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ThemeConfig(AppConfig):
|
||||
name = 'theme'
|
||||
1
theme/static_src/.gitignore
vendored
Normal file
1
theme/static_src/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
||||
1642
theme/static_src/package-lock.json
generated
Normal file
1642
theme/static_src/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
theme/static_src/package.json
Normal file
28
theme/static_src/package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "theme",
|
||||
"version": "3.8.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"start": "npm run dev",
|
||||
"build": "npm run build:clean && npm run build:tailwind",
|
||||
"build:clean": "rimraf ../static/css/dist",
|
||||
"build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css --minify",
|
||||
"dev": "cross-env NODE_ENV=development tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css -w",
|
||||
"tailwindcss": "node ./node_modules/tailwindcss/lib/cli.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"cross-env": "^7.0.3",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-nested": "^6.0.1",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"rimraf": "^5.0.5",
|
||||
"tailwindcss": "^3.4.0"
|
||||
}
|
||||
}
|
||||
7
theme/static_src/postcss.config.js
Normal file
7
theme/static_src/postcss.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"postcss-import": {},
|
||||
"postcss-simple-vars": {},
|
||||
"postcss-nested": {}
|
||||
},
|
||||
}
|
||||
3
theme/static_src/src/styles.css
Normal file
3
theme/static_src/src/styles.css
Normal file
@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
57
theme/static_src/tailwind.config.js
Normal file
57
theme/static_src/tailwind.config.js
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* This is a minimal config.
|
||||
*
|
||||
* If you need the full config, get it from here:
|
||||
* https://unpkg.com/browse/tailwindcss@latest/stubs/defaultConfig.stub.js
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
content: [
|
||||
/**
|
||||
* HTML. Paths to Django template files that will contain Tailwind CSS classes.
|
||||
*/
|
||||
|
||||
/* Templates within theme app (<tailwind_app_name>/templates), e.g. base.html. */
|
||||
'../templates/**/*.html',
|
||||
|
||||
/*
|
||||
* Main templates directory of the project (BASE_DIR/templates).
|
||||
* Adjust the following line to match your project structure.
|
||||
*/
|
||||
'../../templates/**/*.html',
|
||||
|
||||
/*
|
||||
* Templates in other django apps (BASE_DIR/<any_app_name>/templates).
|
||||
* Adjust the following line to match your project structure.
|
||||
*/
|
||||
'../../**/templates/**/*.html',
|
||||
|
||||
/**
|
||||
* JS: If you use Tailwind CSS in JavaScript, uncomment the following lines and make sure
|
||||
* patterns match your project structure.
|
||||
*/
|
||||
/* JS 1: Ignore any JavaScript in node_modules folder. */
|
||||
// '!../../**/node_modules',
|
||||
/* JS 2: Process all JavaScript files in the project. */
|
||||
// '../../**/*.js',
|
||||
|
||||
/**
|
||||
* Python: If you use Tailwind CSS classes in Python, uncomment the following line
|
||||
* and make sure the pattern below matches your project structure.
|
||||
*/
|
||||
// '../../**/*.py'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [
|
||||
/**
|
||||
* '@tailwindcss/forms' is the forms plugin that provides a minimal styling
|
||||
* for forms. If you don't like it or have own styling for forms,
|
||||
* comment the line below to disable '@tailwindcss/forms'.
|
||||
*/
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/aspect-ratio'),
|
||||
],
|
||||
}
|
||||
19
theme/templates/base.html
Normal file
19
theme/templates/base.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% load static tailwind_tags %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Django Tailwind</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
{% tailwind_css %}
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-50 font-serif leading-normal tracking-normal">
|
||||
<div class="container mx-auto">
|
||||
<section class="flex items-center justify-center h-screen">
|
||||
<h1 class="text-5xl">Django + Tailwind = ❤️</h1>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user