v01 Student Portal - until Call Teacher
This commit is contained in:
parent
bcae639c1b
commit
eb00b2d192
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
53
core/migrations/0001_initial.py
Normal file
53
core/migrations/0001_initial.py
Normal file
@ -0,0 +1,53 @@
|
||||
# Generated by Django 5.2.7 on 2025-12-10 14:54
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Assignment',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('description', models.TextField()),
|
||||
('due_date', models.DateTimeField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Exercise',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('question', models.TextField()),
|
||||
('answer', models.TextField()),
|
||||
('assignment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exercises', to='core.assignment')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Hint',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('hint_text', models.TextField()),
|
||||
('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='hints', to='core.exercise')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Submission',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('submitted_answer', models.TextField()),
|
||||
('is_correct', models.BooleanField(default=False)),
|
||||
('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.exercise')),
|
||||
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
@ -1,3 +1,34 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# Create your models here.
|
||||
class Assignment(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.TextField()
|
||||
due_date = models.DateTimeField()
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
class Exercise(models.Model):
|
||||
assignment = models.ForeignKey(Assignment, related_name='exercises', on_delete=models.CASCADE)
|
||||
question = models.TextField()
|
||||
answer = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
return self.question
|
||||
|
||||
class Submission(models.Model):
|
||||
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE)
|
||||
student = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
submitted_answer = models.TextField()
|
||||
is_correct = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.student.username} - {self.exercise.question}'
|
||||
|
||||
class Hint(models.Model):
|
||||
exercise = models.ForeignKey(Exercise, related_name='hints', on_delete=models.CASCADE)
|
||||
hint_text = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
return self.hint_text
|
||||
|
||||
@ -14,12 +14,17 @@
|
||||
<meta property="twitter:image" content="{{ project_image_url }}">
|
||||
{% endif %}
|
||||
{% load static %}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block content %}{% endblock %}
|
||||
{% block extra_js %}{% endblock %}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
63
core/templates/core/assignment_detail.html
Normal file
63
core/templates/core/assignment_detail.html
Normal file
@ -0,0 +1,63 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<h1 class="my-4">{{ assignment.title }}</h1>
|
||||
<p>{{ assignment.description }}</p>
|
||||
<hr>
|
||||
<h3>Exercises</h3>
|
||||
{% for exercise in assignment.exercises.all %}
|
||||
<div class="card my-3">
|
||||
<div class="card-body">
|
||||
<p class="card-text">{{ exercise.question }}</p>
|
||||
<form method="post" action="{% url 'core:assignment_detail' assignment.id %}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="exercise_id" value="{{ exercise.id }}">
|
||||
<div class="form-group">
|
||||
<textarea class="form-control" name="answer" rows="3" placeholder="Your answer"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<button type="button" class="btn btn-info get-hint" data-exercise-id="{{ exercise.id }}">Get Hint</button>
|
||||
<button type="button" class="btn btn-danger call-teacher">Call Teacher</button>
|
||||
</form>
|
||||
<div class="hint-container mt-3" id="hint-for-{{ exercise.id }}" style="display: none;">
|
||||
<div class="alert alert-info hint-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const hintButtons = document.querySelectorAll('.get-hint');
|
||||
hintButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const exerciseId = this.dataset.exerciseId;
|
||||
fetch(`/hint/${exerciseId}/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const hintContainer = document.querySelector(`#hint-for-${exerciseId}`);
|
||||
const hintText = hintContainer.querySelector('.hint-text');
|
||||
hintText.textContent = data.hint;
|
||||
hintContainer.style.display = 'block';
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const callTeacherButtons = document.querySelectorAll('.call-teacher');
|
||||
callTeacherButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
fetch(`/call-teacher/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
alert(data.message);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
||||
@ -1,145 +1,53 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{{ project_name }}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@keyframes bg-pan {
|
||||
0% {
|
||||
background-position: 0% 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2.5rem 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
|
||||
font-weight: 700;
|
||||
margin: 0 0 1.2rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.loader {
|
||||
margin: 1.5rem auto;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.runtime code {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
padding: 0.15rem 0.45rem;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block title %}CodeCraft - Your Coding Challenge Platform{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your app…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
<div class="container-fluid">
|
||||
|
||||
<header class="hero">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 mx-auto">
|
||||
<h1 class="display-4">Welcome to CodeCraft</h1>
|
||||
<p class="lead">The ultimate platform for coding challenges and assignments. Sharpen your skills, compete with peers, and get feedback from instructors.</p>
|
||||
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
|
||||
<a href="#" class="btn btn-primary btn-lg">Student Portal</a>
|
||||
<a href="#" class="btn btn-secondary btn-lg">Teacher Login</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
|
||||
<p class="runtime">
|
||||
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
|
||||
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
|
||||
</footer>
|
||||
{% endblock %}
|
||||
</header>
|
||||
|
||||
<section class="features-section">
|
||||
<div class="container">
|
||||
<div class="row text-center">
|
||||
<div class="col-lg-4 mb-4">
|
||||
<div class="feature-card h-100">
|
||||
<div class="icon"><i class="fas fa-tasks"></i></div>
|
||||
<h3 class="h4">Diverse Challenges</h3>
|
||||
<p>From simple algorithms to complex data structures, we have a wide range of challenges to test your skills.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 mb-4">
|
||||
<div class="feature-card h-100">
|
||||
<div class="icon"><i class="fas fa-lightbulb"></i></div>
|
||||
<h3 class="h4">Hint System</h3>
|
||||
<p>Stuck on a problem? Our hint system will guide you towards the solution without giving it away.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 mb-4">
|
||||
<div class="feature-card h-100">
|
||||
<div class="icon"><i class="fas fa-chalkboard-teacher"></i></div>
|
||||
<h3 class="h4">Instructor Support</h3>
|
||||
<p>Teachers can create assignments, provide feedback, and even queue up to help students in real-time.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
18
core/templates/core/student_dashboard.html
Normal file
18
core/templates/core/student_dashboard.html
Normal file
@ -0,0 +1,18 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<h1 class="my-4">Student Dashboard</h1>
|
||||
<div class="list-group">
|
||||
{% for assignment in assignments %}
|
||||
<a href="{% url 'core:assignment_detail' assignment.id %}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">{{ assignment.title }}</h5>
|
||||
<small>Due: {{ assignment.due_date }}</small>
|
||||
</div>
|
||||
<p class="mb-1">{{ assignment.description }}</p>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -1,7 +1,13 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import home
|
||||
from .views import home, student_dashboard, assignment_detail, get_hint, call_teacher
|
||||
|
||||
app_name = "core"
|
||||
|
||||
urlpatterns = [
|
||||
path("", home, name="home"),
|
||||
path("dashboard/", student_dashboard, name="student_dashboard"),
|
||||
path("assignment/<int:assignment_id>/", assignment_detail, name="assignment_detail"),
|
||||
path("hint/<int:exercise_id>/", get_hint, name="get_hint"),
|
||||
path("call-teacher/", call_teacher, name="call_teacher"),
|
||||
]
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
|
||||
from django import get_version as django_version
|
||||
from django.shortcuts import render
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import Assignment, Exercise, Hint, Submission
|
||||
|
||||
def home(request):
|
||||
"""Render the landing screen with loader and environment details."""
|
||||
"""Render the landing screen with loader and environment details."""
|
||||
host_name = request.get_host().lower()
|
||||
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
|
||||
now = timezone.now()
|
||||
@ -23,3 +26,44 @@ def home(request):
|
||||
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
|
||||
}
|
||||
return render(request, "core/index.html", context)
|
||||
|
||||
def student_dashboard(request):
|
||||
assignments = Assignment.objects.all()
|
||||
return render(request, "core/student_dashboard.html", {"assignments": assignments})
|
||||
|
||||
def assignment_detail(request, assignment_id):
|
||||
assignment = get_object_or_404(Assignment, pk=assignment_id)
|
||||
if request.method == 'POST':
|
||||
exercise_id = request.POST.get('exercise_id')
|
||||
submitted_answer = request.POST.get('answer')
|
||||
exercise = get_object_or_404(Exercise, pk=exercise_id)
|
||||
submission, created = Submission.objects.get_or_create(
|
||||
exercise=exercise,
|
||||
student=request.user,
|
||||
defaults={'submitted_answer': submitted_answer}
|
||||
)
|
||||
if not created:
|
||||
submission.submitted_answer = submitted_answer
|
||||
submission.save()
|
||||
|
||||
if submission.submitted_answer.lower() == exercise.answer.lower():
|
||||
submission.is_correct = True
|
||||
submission.save()
|
||||
# You might want to add a message here
|
||||
else:
|
||||
submission.is_correct = False
|
||||
submission.save()
|
||||
|
||||
return render(request, "core/assignment_detail.html", {"assignment": assignment})
|
||||
|
||||
def get_hint(request, exercise_id):
|
||||
exercise = get_object_or_404(Exercise, pk=exercise_id)
|
||||
hints = exercise.hints.all()
|
||||
if hints:
|
||||
hint = random.choice(hints)
|
||||
return JsonResponse({'hint': hint.hint_text})
|
||||
return JsonResponse({'hint': 'No hints available for this exercise.'})
|
||||
|
||||
def call_teacher(request):
|
||||
# In a real application, this would trigger a notification to the teacher
|
||||
return JsonResponse({'message': 'A teacher has been called to help you.'})
|
||||
|
||||
@ -1,4 +1,99 @@
|
||||
/* Custom styles for the application */
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
:root {
|
||||
--primary-color: #4285F4;
|
||||
--secondary-color: #FBBC05;
|
||||
--accent-color: #34A853;
|
||||
--neutral-light-gray: #F8F9FA;
|
||||
--neutral-dark-text: #202124;
|
||||
--font-headings: 'Poppins', sans-serif;
|
||||
--font-body: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-body);
|
||||
color: var(--neutral-dark-text);
|
||||
background-color: #fff;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-headings);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-family: var(--font-headings);
|
||||
font-weight: 600;
|
||||
border-radius: 8px;
|
||||
padding: 12px 28px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #3367D6;
|
||||
border-color: #3367D6;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--secondary-color);
|
||||
border-color: var(--secondary-color);
|
||||
color: var(--neutral-dark-text);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #F9A825;
|
||||
border-color: #F9A825;
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding: 100px 0;
|
||||
background: linear-gradient(135deg, #E3F2FD, #FFFFFF);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 3.5rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 20px;
|
||||
color: var(--neutral-dark-text);
|
||||
}
|
||||
|
||||
.hero .lead {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 40px;
|
||||
color: #5f6368;
|
||||
}
|
||||
|
||||
.features-section {
|
||||
padding: 80px 0;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
background-color: var(--neutral-light-gray);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
transform: translateY(-10px);
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.feature-card .icon {
|
||||
font-size: 3rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@ -1,21 +1,99 @@
|
||||
|
||||
/* Custom styles for the application */
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
--primary-color: #4285F4;
|
||||
--secondary-color: #FBBC05;
|
||||
--accent-color: #34A853;
|
||||
--neutral-light-gray: #F8F9FA;
|
||||
--neutral-dark-text: #202124;
|
||||
--font-headings: 'Poppins', sans-serif;
|
||||
--font-body: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
font-family: var(--font-body);
|
||||
color: var(--neutral-dark-text);
|
||||
background-color: #fff;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-headings);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-family: var(--font-headings);
|
||||
font-weight: 600;
|
||||
border-radius: 8px;
|
||||
padding: 12px 28px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #3367D6;
|
||||
border-color: #3367D6;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--secondary-color);
|
||||
border-color: var(--secondary-color);
|
||||
color: var(--neutral-dark-text);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #F9A825;
|
||||
border-color: #F9A825;
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding: 100px 0;
|
||||
background: linear-gradient(135deg, #E3F2FD, #FFFFFF);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 3.5rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 20px;
|
||||
color: var(--neutral-dark-text);
|
||||
}
|
||||
|
||||
.hero .lead {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 40px;
|
||||
color: #5f6368;
|
||||
}
|
||||
|
||||
.features-section {
|
||||
padding: 80px 0;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
background-color: var(--neutral-light-gray);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
transform: translateY(-10px);
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.feature-card .icon {
|
||||
font-size: 3rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user