diff --git a/Blogger/Blogger/__init__.py b/Blogger/Blogger/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Blogger/Blogger/asgi.py b/Blogger/Blogger/asgi.py new file mode 100644 index 0000000..52ba7b4 --- /dev/null +++ b/Blogger/Blogger/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for Blogger project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Blogger.settings') + +application = get_asgi_application() diff --git a/Blogger/Blogger/settings.py b/Blogger/Blogger/settings.py new file mode 100644 index 0000000..fe69b7a --- /dev/null +++ b/Blogger/Blogger/settings.py @@ -0,0 +1,124 @@ +""" +Django settings for Blogger project. + +Generated by 'django-admin startproject' using Django 6.0.4. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/6.0/ref/settings/ +""" + +from pathlib import Path +import os + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-r-!20^o(xsf3i)-s1#53*v!(wj0&@=vp5#gu8r#k48zeq1l2k)' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'main', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'Blogger.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'Blogger.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/6.0/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/6.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +# TIME_ZONE = 'UTC' +TIME_ZONE = 'Asia/Riyadh' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/6.0/howto/static-files/ + +STATIC_URL = 'static/' + + +MEDIA_URL = '/media/' +MEDIA_ROOT =os.path.join(BASE_DIR, 'media') diff --git a/Blogger/Blogger/urls.py b/Blogger/Blogger/urls.py new file mode 100644 index 0000000..fa7ff89 --- /dev/null +++ b/Blogger/Blogger/urls.py @@ -0,0 +1,25 @@ +""" +URL configuration for Blogger project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/6.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path,include +from django.conf.urls.static import static +from . import settings + +urlpatterns = [ + path('admin/', admin.site.urls), + path("", include("main.urls")) +] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) diff --git a/Blogger/Blogger/wsgi.py b/Blogger/Blogger/wsgi.py new file mode 100644 index 0000000..03bf872 --- /dev/null +++ b/Blogger/Blogger/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for Blogger project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Blogger.settings') + +application = get_wsgi_application() diff --git a/Blogger/main/__init__.py b/Blogger/main/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Blogger/main/admin.py b/Blogger/main/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/Blogger/main/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/Blogger/main/apps.py b/Blogger/main/apps.py new file mode 100644 index 0000000..833bff6 --- /dev/null +++ b/Blogger/main/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class MainConfig(AppConfig): + name = 'main' diff --git a/Blogger/main/migrations/0001_initial.py b/Blogger/main/migrations/0001_initial.py new file mode 100644 index 0000000..a72b6e3 --- /dev/null +++ b/Blogger/main/migrations/0001_initial.py @@ -0,0 +1,24 @@ +# Generated by Django 6.0.4 on 2026-04-15 01:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Post', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=2048)), + ('content', models.TextField()), + ('is_published', models.BooleanField(default=True)), + ('published_at', models.DateTimeField(auto_now_add=True)), + ], + ), + ] diff --git a/Blogger/main/migrations/0002_post_poster.py b/Blogger/main/migrations/0002_post_poster.py new file mode 100644 index 0000000..2445d89 --- /dev/null +++ b/Blogger/main/migrations/0002_post_poster.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.4 on 2026-04-16 00:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='post', + name='poster', + field=models.ImageField(default='images/default.jpg', upload_to='images/'), + ), + ] diff --git a/Blogger/main/migrations/__init__.py b/Blogger/main/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Blogger/main/models.py b/Blogger/main/models.py new file mode 100644 index 0000000..5b2408d --- /dev/null +++ b/Blogger/main/models.py @@ -0,0 +1,10 @@ +from django.db import models + +# Create your models here. + +class Post(models.Model): + title = models.CharField(max_length=2048) + content = models.TextField() + is_published = models.BooleanField(default=True) + published_at = models.DateTimeField(auto_now_add=True) + poster = models.ImageField(upload_to="images/", default="images/default.jpg") diff --git a/Blogger/main/static/css/style.css b/Blogger/main/static/css/style.css new file mode 100644 index 0000000..5c7b0da --- /dev/null +++ b/Blogger/main/static/css/style.css @@ -0,0 +1,559 @@ + +@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@300;400;500;700;900&family=IBM+Plex+Sans+Arabic:wght@300;400;500;600&display=swap'); + +/* ── Fonts ── */ +* { + font-family: 'IBM Plex Sans Arabic', 'Tajawal', sans-serif; +} + +h1, h2, h3, h4, h5, h6, +.blogger-brand, +.blogger-footer-brand { + font-family: 'Tajawal', sans-serif; +} + +/* ── Light Mode ── */ +:root, +[data-theme="light"] { + --bg-primary: #F8F5F0; + --bg-secondary: #EEEAE3; + --bg-card: #FFFFFF; + --bg-navbar: #FFFFFF; + --bg-footer: #1A1714; + + --text-primary: #1A1A1A; + --text-secondary: #555555; + --text-muted: #888888; + --text-footer: #C8B99A; + --text-footer-head: #F0EDE8; + + --accent-gold: #C8972B; + --accent-gold-hover:#A87820; + --accent-gold-light:#F5E6C4; + + --border-color: #E0DAD0; + --shadow-sm: 0 2px 8px rgba(0,0,0,0.08); + --shadow-md: 0 4px 20px rgba(0,0,0,0.12); + --shadow-lg: 0 8px 40px rgba(0,0,0,0.16); + + --navbar-border: rgba(200, 151, 43, 0.2); + --dropdown-bg: #FFFFFF; + --dropdown-hover: #F8F5F0; + + --btn-outline-text: #1A1A1A; + --btn-outline-border: #C8972B; +} + +/* ── Dark Mode ── */ +[data-theme="dark"] { + --bg-primary: #0F0F0F; + --bg-secondary: #1A1A1A; + --bg-card: #1E1E1E; + --bg-navbar: #111111; + --bg-footer: #080808; + + --text-primary: #F0EDE8; + --text-secondary: #B0A89E; + --text-muted: #777777; + --text-footer: #8A7D6E; + --text-footer-head: #D4C9BC; + + --accent-gold: #C8972B; + --accent-gold-hover:#E0AA40; + --accent-gold-light:#2A2010; + + --border-color: #2A2A2A; + --shadow-sm: 0 2px 8px rgba(0,0,0,0.3); + --shadow-md: 0 4px 20px rgba(0,0,0,0.4); + --shadow-lg: 0 8px 40px rgba(0,0,0,0.5); + + --navbar-border: rgba(200, 151, 43, 0.15); + --dropdown-bg: #1E1E1E; + --dropdown-hover: #252525; + + --btn-outline-text: #F0EDE8; + --btn-outline-border: #C8972B; +} + +/* ── Base ── */ +html, body { + background-color: var(--bg-primary); + color: var(--text-primary) !important; + min-height: 100vh; + transition: background-color 0.3s ease, color 0.3s ease; + display: flex; + flex-direction: column; +} + +html { + scroll-behavior: smooth; +} + +main { + flex: 1; +} + +a { + color: var(--accent-gold); + text-decoration: none; + transition: color 0.2s ease; +} + +a:hover { + color: var(--accent-gold-hover); +} + +/* ── Scrollbar ── */ +::-webkit-scrollbar { width: 6px; } +::-webkit-scrollbar-track { background: var(--bg-secondary); } +::-webkit-scrollbar-thumb { background: var(--accent-gold); border-radius: 3px; } + + +/* ══════════════════════════════ + NAVBAR +══════════════════════════════ */ +.blogger-navbar { + background-color: var(--bg-navbar) !important; + border-bottom: 1px solid var(--navbar-border); + box-shadow: var(--shadow-sm); + transition: background-color 0.3s ease; + padding: 0.75rem 0; +} + +.blogger-brand { + font-family: 'Tajawal', sans-serif; + font-weight: 700; + font-size: 1.25rem; + color: var(--text-primary) !important; + display: flex; + align-items: center; + gap: 0.5rem; + letter-spacing: 0.5px; +} + +.blogger-brand .brand-icon { + width: 32px; + height: 32px; + background-color: var(--accent-gold); + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + color: #fff; + font-size: 1rem; + font-weight: 700; + font-family: 'Tajawal', sans-serif; +} + +.blogger-navbar .nav-link { + color: var(--text-secondary) !important; + font-weight: 500; + font-size: 0.95rem; + padding: 0.4rem 0.75rem !important; + border-radius: 6px; + transition: color 0.2s ease, background-color 0.2s ease; +} + +.blogger-navbar .nav-link:hover, +.blogger-navbar .nav-link.active { + color: var(--accent-gold) !important; + background-color: var(--accent-gold-light); +} + +[data-theme="dark"] .blogger-navbar .navbar-toggler-icon { + filter: invert(1); +} + + +/* ══════════════════════════════ + BUTTONS +══════════════════════════════ */ +.blogger-btn-outline { + background: transparent; + color: var(--btn-outline-text); + border: 1px solid var(--btn-outline-border); + border-radius: 8px; + padding: 0.35rem 0.85rem; + font-size: 0.85rem; + font-weight: 500; + transition: all 0.2s ease; +} + +.blogger-btn-outline:hover { + background-color: var(--accent-gold); + color: #fff; + border-color: var(--accent-gold); +} + +.blogger-btn-gold { + background-color: var(--accent-gold); + color: #fff !important; + border: none; + border-radius: 8px; + padding: 0.35rem 0.85rem; + font-size: 0.85rem; + font-weight: 600; + transition: background-color 0.2s ease, transform 0.1s ease; +} + +.blogger-btn-gold:hover { + background-color: var(--accent-gold-hover); + transform: translateY(-1px); +} + +.blogger-btn-lg { + padding: 0.75rem 2rem; + font-size: 1rem; + border-radius: 10px; +} + + +/* ══════════════════════════════ + CARDS +══════════════════════════════ */ +.blogger-card { + background-color: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 14px; + overflow: hidden; + box-shadow: var(--shadow-sm); + transition: transform 0.25s ease, box-shadow 0.25s ease; + cursor: pointer; +} + +.blogger-card:hover { + transform: translateY(-6px); + box-shadow: var(--shadow-lg); +} + +.blogger-card-body { + padding: 1.25rem; +} + +.blogger-card-title { + font-family: 'Tajawal', sans-serif; + font-weight: 700; + font-size: 1.1rem; + color: var(--text-primary); + margin-bottom: 0.4rem; +} + +.blogger-card-text { + font-size: 0.88rem; + color: var(--text-secondary); + line-height: 1.6; + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.blogger-card-meta { + font-size: 0.8rem; + color: var(--text-muted); + display: flex; + align-items: center; + gap: 0.35rem; + margin-top: 1rem; + padding-top: 0.75rem; + border-top: 1px solid var(--border-color); +} + + +/* ══════════════════════════════ + HERO +══════════════════════════════ */ +.blogger-hero { + background-color: var(--bg-secondary); + border-bottom: 1px solid var(--border-color); + padding: 5rem 0 4rem; + text-align: center; +} + +.blogger-hero-title { + font-family: 'Tajawal', sans-serif; + font-weight: 900; + font-size: clamp(2rem, 5vw, 3rem); + color: var(--text-primary); + line-height: 1.2; +} + +.blogger-hero-subtitle { + font-size: 1rem; + color: var(--text-secondary); + max-width: 500px; + margin: 0 auto; + line-height: 1.7; +} + +.blogger-gold-line { + width: 60px; + height: 3px; + background-color: var(--accent-gold); + border-radius: 2px; + margin: 1rem auto; +} + + +/* ══════════════════════════════ + SECTION TITLES +══════════════════════════════ */ +.blogger-section-title { + font-family: 'Tajawal', sans-serif; + font-weight: 700; + font-size: clamp(1.4rem, 3vw, 1.75rem); + color: var(--text-primary); +} + +.blogger-section-title span { + color: var(--accent-gold); +} + +.blogger-section-subtitle { + color: var(--text-secondary); + font-size: 0.95rem; + max-width: 550px; +} + + +/* ══════════════════════════════ + FORM PAGE +══════════════════════════════ */ +.blogger-form-card { + background-color: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 14px; + padding: 2rem; + box-shadow: var(--shadow-md); + max-width: 700px; +} + +.blogger-field-label { + display: block; + font-size: 0.85rem; + font-weight: 600; + color: var(--text-secondary); + margin-bottom: 0.4rem; +} + +.blogger-field-input, +.blogger-field-textarea { + width: 100%; + padding: 0.6rem 0.9rem; + background-color: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: 8px; + color: var(--text-primary); + font-size: 0.95rem; + font-family: 'IBM Plex Sans Arabic', sans-serif; + outline: none; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.blogger-field-input:focus, +.blogger-field-textarea:focus { + border-color: var(--accent-gold); + box-shadow: 0 0 0 3px rgba(200, 151, 43, 0.15); + background-color: var(--bg-card); +} + +/* input{ + background-color: gray; +} */ + +.blogger-field-textarea { + resize: vertical; + min-height: 200px; + line-height: 1.6; +} + +.blogger-publish-row { + display: flex; + align-items: flex-start; + gap: 0.6rem; + padding: 0.85rem 1rem; + background-color: var(--bg-secondary); + border: 1px solid var(--border-color); + border-radius: 8px; + cursor: pointer; +} + +.blogger-publish-row input[type="checkbox"] { + width: 17px; + height: 17px; + accent-color: var(--accent-gold); + cursor: pointer; + margin-top: 2px; + flex-shrink: 0; +} + +.blogger-publish-row label { + font-size: 0.9rem; + color: var(--text-primary); + cursor: pointer; + margin: 0; +} + +.blogger-publish-row label small { + display: block; + color: var(--text-muted); + font-size: 0.78rem; + margin-top: 0.1rem; +} + +.blogger-error-msg { + background-color: rgba(200, 50, 43, 0.08); + border: 1px solid rgba(200, 50, 43, 0.25); + border-left: 4px solid #c0392b; + border-radius: 8px; + padding: 0.75rem 1rem; + color: #c0392b; + font-size: 0.88rem; + margin-bottom: 1.25rem; +} + + +/* ══════════════════════════════ + FOOTER +══════════════════════════════ */ +.blogger-footer { + background-color: var(--bg-footer); + transition: background-color 0.3s ease; +} + +.blogger-footer-brand { + font-family: 'Tajawal', sans-serif; + font-weight: 700; + font-size: 1.15rem; + color: var(--text-footer-head); +} + +.blogger-footer-text { + color: var(--text-footer); + font-size: 0.88rem; + line-height: 1.7; +} + +.blogger-footer-heading { + color: var(--text-footer-head); + font-family: 'Tajawal', sans-serif; + font-weight: 600; + font-size: 0.9rem; + margin-bottom: 0.875rem; + letter-spacing: 0.5px; +} + +.blogger-footer-links li { + margin-bottom: 0.45rem; +} + +.blogger-footer-links a, +.blogger-footer-links li { + color: var(--text-footer); + font-size: 0.85rem; + transition: color 0.2s ease; +} + +.blogger-footer-links a:hover { + color: var(--accent-gold); +} + +.blogger-footer-divider { + border-color: rgba(200, 151, 43, 0.15); +} + +.blogger-footer-copy { + color: var(--text-footer); + font-size: 0.8rem; +} + + +/* ══════════════════════════════ + UTILITIES +══════════════════════════════ */ +.text-gold { color: var(--accent-gold) !important; } +.bg-card { background-color: var(--bg-card) !important; } + +.blogger-divider { + border: none; + height: 1px; + background: var(--border-color); + margin: 2rem 0; +} + +.blogger-page-header { + padding-bottom: 1.25rem; + margin-bottom: 2rem; + border-bottom: 1px solid var(--border-color); +} + +.blogger-page-title { + font-family: 'Tajawal', sans-serif; + font-size: clamp(1.5rem, 3vw, 2rem); + font-weight: 700; + color: var(--text-primary); + margin-bottom: 0.25rem; +} + +.blogger-page-sub { + color: var(--text-muted); + font-size: 0.9rem; +} + + +/* ══════════════════════════════ + ANIMATIONS +══════════════════════════════ */ +@keyframes fadeInUp { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} + +.fade-in-up { animation: fadeInUp 0.5s ease forwards; } +.fade-in-up-delay-1 { animation: fadeInUp 0.5s ease 0.1s forwards; opacity: 0; } +.fade-in-up-delay-2 { animation: fadeInUp 0.5s ease 0.2s forwards; opacity: 0; } +.fade-in-up-delay-3 { animation: fadeInUp 0.5s ease 0.3s forwards; opacity: 0; } + + +/* ══════════════════════════════ + RESPONSIVE +══════════════════════════════ */ +@media (max-width: 768px) { + .blogger-hero { + padding: 3.5rem 0 3rem; + } + + .blogger-form-card { + padding: 1.5rem; + } +} + +@media (max-width: 576px) { + .blogger-hero-title { + font-size: 1.75rem; + } +} + +::-webkit-scrollbar-thumb { background: var(--accent-gold);} +::-webkit-scrollbar-thumb:hover{background-color: blue;} + +/* صورة البوست */ +img { + border-radius: 10px; + max-height: 400px; + object-fit: cover; +} + +/* صورة الأبديت */ +.update-preview-img { + height: 80px; + border-radius: 6px; + object-fit: cover; +} + +/* file input */ +.form-control { + background: var(--bg-primary); + color: var(--text-primary); + border-color: var(--border-color); +} \ No newline at end of file diff --git a/Blogger/main/templates/main/add_post.html b/Blogger/main/templates/main/add_post.html new file mode 100644 index 0000000..d8a20e4 --- /dev/null +++ b/Blogger/main/templates/main/add_post.html @@ -0,0 +1,84 @@ +{% extends 'main/base.html' %} +{% load static %} + +{% block title %}Blogger — New Post{% endblock %} + +{% block content %} + +
+
+ + +
+

+ Write a New Post +

+

Share your thoughts with the world.

+
+ + +
+ + + {% if error %} +
+ {{ error }} +
+ {% endif %} + + +
+ {% csrf_token %} + + +
+ + +
+ + +
+ + + + +
+ +
+ + +
+ + + Cancel + +
+ +
+
+ +
+
+ +{% endblock %} diff --git a/Blogger/main/templates/main/base.html b/Blogger/main/templates/main/base.html new file mode 100644 index 0000000..41ccaed --- /dev/null +++ b/Blogger/main/templates/main/base.html @@ -0,0 +1,168 @@ +{% load static %} + + + + + + {% block title %}Blogger{% endblock %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {% block content %}{% endblock %} +
+ + + + + + + + + + + + + + + + diff --git a/Blogger/main/templates/main/detail_post.html b/Blogger/main/templates/main/detail_post.html new file mode 100644 index 0000000..3836f17 --- /dev/null +++ b/Blogger/main/templates/main/detail_post.html @@ -0,0 +1,98 @@ +{% extends 'main/base.html' %} +{% load static %} + +{% block title %}{{ post.title }}{% endblock %} + +{% block content %} +
+
+ +
+ + + {% if post.poster %} + + {% endif %} + + +
+ + {{ post.published_at|date:"F j, Y" }} + + + {{ post.published_at|time:"g:i A" }} +
+ + +

{{ post.title }}

+ + +

{{ post.content }}

+ +
+ + +
+ + + + Update + + + + + + + + + + Back + + +
+
+ +
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/Blogger/main/templates/main/index.html b/Blogger/main/templates/main/index.html new file mode 100644 index 0000000..12be824 --- /dev/null +++ b/Blogger/main/templates/main/index.html @@ -0,0 +1,96 @@ +{% extends 'main/base.html' %} +{% load static %} + +{% block title %}Blogger — Home{% endblock %} + +{% block content %} + + +
+
+ +

+ Welcome to Blogger +

+ +

+ Latest Posts +

+ +
+ +

+ Read the freshest stories, thoughts, and ideas — published by our community. +

+ + + Write a Post + + +
+
+ + + + +
+
+ + +
+

+ Recent Stories +

+

+ {{ posts.count }} post{{ posts.count|pluralize }} published so far +

+
+
+ + + {% if posts %} +
+ {% for post in posts %} +
+
+
+ +

{{ post.title }}

+ + + + Read More + + +
+ + {{ post.published_at|date:"F j, Y" }} + + + {{ post.published_at|time:"g:i A" }} +
+ +
+
+
+ {% endfor %} +
+ + {% else %} + +
+ +

No posts yet

+

Be the first to share your thoughts.

+ + Write the First Post + +
+ {% endif %} + +
+
+ + +{% endblock %} diff --git a/Blogger/main/templates/main/update_post.html b/Blogger/main/templates/main/update_post.html new file mode 100644 index 0000000..df34de0 --- /dev/null +++ b/Blogger/main/templates/main/update_post.html @@ -0,0 +1,77 @@ +{% extends 'main/base.html' %} +{% load static %} + +{% block title %}Update — {{ post.title }}{% endblock %} + +{% block content %} +
+
+ +
+

+ Update Post +

+

Edit your post content below.

+
+ +
+
+ {% csrf_token %} + + +
+ + +
+ + +
+ + +
+ + +
+ + {% if post.poster %} + + {% endif %} + +
+ +
+ +
+ + + Cancel + +
+ +
+
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/Blogger/main/tests.py b/Blogger/main/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/Blogger/main/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/Blogger/main/urls.py b/Blogger/main/urls.py new file mode 100644 index 0000000..c646c8f --- /dev/null +++ b/Blogger/main/urls.py @@ -0,0 +1,12 @@ +from django.urls import path +from . import views + +app_name="main" + +urlpatterns = [ + path('', views.home_view, name='home_view'), + path('add/', views.add_post_view, name='add_post_view'), + path('details//', views.detail_post_view, name='detail_post_view'), + path('update//', views.update_post_view, name='update_post_view'), + path('delete//', views.delete_post_view, name='delete_post_view'), +] \ No newline at end of file diff --git a/Blogger/main/views.py b/Blogger/main/views.py new file mode 100644 index 0000000..db1b4bd --- /dev/null +++ b/Blogger/main/views.py @@ -0,0 +1,57 @@ +from django.shortcuts import render,redirect +from django.http import HttpRequest,HttpResponse +from .models import Post + +# Create your views here. + + +def home_view(request:HttpRequest): + post=Post.objects.all() + return render(request, 'main/index.html', {'posts': post}) + + +# def add_post_view(request:HttpRequest): +# if request.method == "POST": +# print(request.POST) +# new_post = Post(title=request.POST["title"], content=request.POST["content"],poster=request.FILES["poster"]) +# new_post.save() +# return redirect('main:home_view') +def add_post_view(request: HttpRequest): + if request.method == "POST": + new_post = Post( + title=request.POST["title"], + content=request.POST["content"], + ) + if request.FILES.get("poster"): + new_post.poster = request.FILES["poster"] + new_post.save() + return redirect('main:home_view') + return render(request, "main/add_post.html") + + return render(request, "main/add_post.html") + +def detail_post_view(request:HttpRequest, poster_id:int): + post = Post.objects.get(pk=poster_id) + # print(post.title) + + return render(request, 'main/detail_post.html', {'post':post}) + +def update_post_view(request: HttpRequest, poster_id: int): + post = Post.objects.get(pk=poster_id) + + if request.method == "POST": + post.title = request.POST["title"] + post.content = request.POST["content"] + # if request.FILES.get("poster"): + # post.poster = request.FILES["poster"] + if 'poster' in request.FILES: post.poster= request.FILES["poster"] + post.save() + return redirect('main:detail_post_view', poster_id=post.pk) + return render(request, 'main/update_post.html', {'post': post}) + + +def delete_post_view(request: HttpRequest, poster_id: int): # أضف + post = Post.objects.get(pk=poster_id) + post.delete() + + return redirect('main:home_view') diff --git a/Blogger/manage.py b/Blogger/manage.py new file mode 100644 index 0000000..c7803d0 --- /dev/null +++ b/Blogger/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Blogger.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/Blogger/media/images/MD3.jpg b/Blogger/media/images/MD3.jpg new file mode 100644 index 0000000..2e9d33c Binary files /dev/null and b/Blogger/media/images/MD3.jpg differ diff --git a/Blogger/media/images/battlefield-4.jpg b/Blogger/media/images/battlefield-4.jpg new file mode 100644 index 0000000..fe2efbe Binary files /dev/null and b/Blogger/media/images/battlefield-4.jpg differ diff --git a/Blogger/media/images/default.jpg b/Blogger/media/images/default.jpg new file mode 100644 index 0000000..f2a08da Binary files /dev/null and b/Blogger/media/images/default.jpg differ