diff --git a/assets/css/custom.css b/assets/css/custom.css index 6247e42..2b9cf5e 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -1,118 +1,8 @@ - -/* - Custom Styles for Personal Portfolio -*/ - -:root { - --primary-color: #3B82F6; - --secondary-color: #10B981; - --background-color: #F9FAFB; - --surface-color: #FFFFFF; - --text-color: #1F2937; - --light-text-color: #6B7280; - --border-radius: 0.5rem; - --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); -} - body { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; - background-color: var(--background-color); - color: var(--text-color); + background-color: #f8f9fa; } -.navbar { - transition: background-color 0.3s ease-in-out; -} - -.navbar-scrolled { - background-color: var(--surface-color); - box-shadow: var(--shadow-md); -} - -.hero { +.card-header { + background-color: #343a40; color: white; - padding: 8rem 0; - position: relative; - text-align: center; -} - -.hero::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-image: linear-gradient(to right, rgba(59, 130, 246, 0.8), rgba(16, 185, 129, 0.8)), url('../images/hero-kittens-45170.jpg'); - background-size: cover; - background-position: center; - z-index: -1; -} - -.hero h1 { - font-size: 3.5rem; - font-weight: 700; -} - -.hero p { - font-size: 1.25rem; -} - -.btn-primary { - background-color: var(--primary-color); - border-color: var(--primary-color); - padding: 0.75rem 1.5rem; - border-radius: var(--border-radius); - font-weight: 600; -} - -.btn-primary:hover { - opacity: 0.9; - background-color: var(--primary-color); - border-color: var(--primary-color); -} - -.section { - padding: 5rem 0; -} - -.section-title { - text-align: center; - margin-bottom: 3rem; - font-size: 2.5rem; - font-weight: 700; -} - -.portfolio-card { - border: none; - border-radius: var(--border-radius); - box-shadow: var(--shadow-md); - overflow: hidden; - transition: transform 0.3s ease, box-shadow 0.3s ease; -} - -.portfolio-card:hover { - transform: translateY(-5px); - box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); -} - -.form-control:focus { - box-shadow: 0 0 0 0.25rem rgba(59, 130, 246, 0.25); - border-color: var(--primary-color); -} - -footer { - background-color: var(--surface-color); - padding: 2rem 0; - border-top: 1px solid #e5e7eb; -} - -#contact-alert { - position: fixed; - top: 1rem; - right: 1rem; - z-index: 1050; - display: none; - min-width: 250px; -} +} \ No newline at end of file diff --git a/db/migrate.php b/db/migrate.php new file mode 100644 index 0000000..00428f7 --- /dev/null +++ b/db/migrate.php @@ -0,0 +1,24 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $migrationsDir = __DIR__ . '/migrations'; + $files = glob($migrationsDir . '/*.sql'); + sort($files); + + foreach ($files as $file) { + echo "Running migration: " . basename($file) . "\n"; + $sql = file_get_contents($file); + $pdo->exec($sql); + } + + echo "Migrations completed successfully.\n"; + +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} + diff --git a/db/migrations/001_initial_schema.sql b/db/migrations/001_initial_schema.sql new file mode 100644 index 0000000..94442f0 --- /dev/null +++ b/db/migrations/001_initial_schema.sql @@ -0,0 +1,23 @@ +CREATE TABLE IF NOT EXISTS `teams` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(255) NOT NULL UNIQUE +); + +CREATE TABLE IF NOT EXISTS `tournaments` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(255) NOT NULL, + `start_date` DATETIME DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS `matches` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `tournament_id` INT NOT NULL, + `round` INT NOT NULL, + `team1_id` INT, + `team2_id` INT, + `winner_id` INT, + FOREIGN KEY (`tournament_id`) REFERENCES `tournaments`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`team1_id`) REFERENCES `teams`(`id`) ON DELETE SET NULL, + FOREIGN KEY (`team2_id`) REFERENCES `teams`(`id`) ON DELETE SET NULL, + FOREIGN KEY (`winner_id`) REFERENCES `teams`(`id`) ON DELETE SET NULL +); diff --git a/includes/footer.php b/includes/footer.php new file mode 100644 index 0000000..970a97b --- /dev/null +++ b/includes/footer.php @@ -0,0 +1,6 @@ + + + + + + diff --git a/includes/header.php b/includes/header.php new file mode 100644 index 0000000..afcdc2c --- /dev/null +++ b/includes/header.php @@ -0,0 +1,32 @@ + + + + + + + Hearthstone Tournament Manager + + + + + +
diff --git a/index.php b/index.php index b51a6a1..11af247 100644 --- a/index.php +++ b/index.php @@ -1,147 +1,16 @@ - - - - - - John Doe - Personal Portfolio - - + - - - - - - +
+

Welcome to the Hearthstone Tournament Manager!

+

This is a simple application to manage your Hearthstone tournaments.

+
+

You can add teams, create tournaments, and manage matches.

+ Manage Teams + Manage Tournaments +
- - - - - - - - - - - - - - - - - -
-
-

Welcome to My Digital Space

-

I build modern, responsive, and beautiful web applications.

- View My Work -
-
- -
-
-
-

About Me

-
-
-

I am a passionate web developer with a love for clean code and user-centric design. With a background in computer science and several years of experience, I specialize in creating dynamic and engaging websites. When I'm not coding, I enjoy hiking and photography.

-
-
-
-
- -
-
-

Portfolio

-
-
-
- A computer screen with code on it. -
-
Project One
-

A brief description of the project, its purpose, and the technologies used. This is a placeholder.

-
-
-
-
-
- A person's hands typing on a laptop. -
-
Project Two
-

A brief description of the project, its purpose, and the technologies used. This is a placeholder.

-
-
-
-
-
- Code on a screen with a blurry background. -
-
Project Three
-

A brief description of the project, its purpose, and the technologies used. This is a placeholder.

-
-
-
-
-
-
- -
-
-

Get In Touch

-
-
-
-
- - -
-
- - -
-
- - -
-
- -
-
-
- For testing purposes, emails may be sent to a default address. Please configure your own SMTP settings in the .env file for production use. -
-
-
-
-
-
- - - - - - - - - - \ No newline at end of file + diff --git a/teams.php b/teams.php new file mode 100644 index 0000000..0950e0e --- /dev/null +++ b/teams.php @@ -0,0 +1,69 @@ +prepare("INSERT INTO teams (name) VALUES (?)"); + $stmt->execute([$teamName]); + $message = '
Team added successfully!
'; + } catch (PDOException $e) { + if ($e->errorInfo[1] == 1062) { // Duplicate entry + $message = '
Error: A team with this name already exists.
'; + } else { + $message = '
Error: ' . $e->getMessage() . '
'; + } + } + } +} + +// Fetch all teams +$teamsStmt = db()->query("SELECT * FROM teams ORDER BY name"); +$teams = $teamsStmt->fetchAll(); + +?> + +
+
+
+
+

Add New Team

+
+
+ +
+
+ + +
+ +
+
+
+
+
+
+
+

Existing Teams

+
+
+
    + 0): ?> + +
  • + + +
  • No teams found.
  • + +
+
+
+
+
+ + diff --git a/tournament_view.php b/tournament_view.php new file mode 100644 index 0000000..0c7ec75 --- /dev/null +++ b/tournament_view.php @@ -0,0 +1,187 @@ +prepare("SELECT * FROM tournaments WHERE id = ?"); +$stmt->execute([$tournamentId]); +$tournament = $stmt->fetch(); + +if (!$tournament) { + header("Location: /tournaments.php"); + exit; +} + +$message = ''; + +// Generate bracket +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['generate_bracket'])) { + // Check if matches already exist + $stmt = db()->prepare("SELECT COUNT(*) FROM matches WHERE tournament_id = ?"); + $stmt->execute([$tournamentId]); + if ($stmt->fetchColumn() == 0) { + $teamsStmt = db()->query("SELECT * FROM teams"); + $teams = $teamsStmt->fetchAll(); + shuffle($teams); + + $round = 1; + $numTeams = count($teams); + + for ($i = 0; $i < $numTeams; $i += 2) { + $team1_id = $teams[$i]['id']; + $team2_id = isset($teams[$i+1]) ? $teams[$i+1]['id'] : null; + + $stmt = db()->prepare("INSERT INTO matches (tournament_id, round, team1_id, team2_id) VALUES (?, ?, ?, ?)"); + $stmt->execute([$tournamentId, $round, $team1_id, $team2_id]); + + if ($team2_id === null) { // Bye week + $matchId = db()->lastInsertId(); + $stmt = db()->prepare("UPDATE matches SET winner_id = ? WHERE id = ?"); + $stmt->execute([$team1_id, $matchId]); + } + } + $message = '
Bracket generated successfully!
'; + } else { + $message = '
Bracket has already been generated.
'; + } +} + +// Update winner +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_winner'])) { + $matchId = $_POST['match_id']; + $winnerId = $_POST['winner_id']; + + $stmt = db()->prepare("UPDATE matches SET winner_id = ? WHERE id = ?"); + $stmt->execute([$winnerId, $matchId]); + $message = '
Winner updated!
'; +} + +// Generate next round +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['next_round'])) { + $stmt = db()->prepare("SELECT MAX(round) FROM matches WHERE tournament_id = ?"); + $stmt->execute([$tournamentId]); + $currentRound = $stmt->fetchColumn(); + + $stmt = db()->prepare("SELECT winner_id FROM matches WHERE tournament_id = ? AND round = ? AND winner_id IS NOT NULL"); + $stmt->execute([$tournamentId, $currentRound]); + $winners = $stmt->fetchAll(PDO::FETCH_COLUMN); + + if (count($winners) > 1) { + $nextRound = $currentRound + 1; + for ($i = 0; $i < count($winners); $i += 2) { + $team1_id = $winners[$i]; + $team2_id = isset($winners[$i+1]) ? $winners[$i+1] : null; + + $stmt = db()->prepare("INSERT INTO matches (tournament_id, round, team1_id, team2_id) VALUES (?, ?, ?, ?)"); + $stmt->execute([$tournamentId, $nextRound, $team1_id, $team2_id]); + + if ($team2_id === null) { // Bye week + $matchId = db()->lastInsertId(); + $stmt = db()->prepare("UPDATE matches SET winner_id = ? WHERE id = ?"); + $stmt->execute([$team1_id, $matchId]); + } + } + $message = '
Next round generated!
'; + } else { + $message = '
Tournament finished!
'; + } +} + + +// Fetch matches +$matchesStmt = db()->prepare(" + SELECT m.id, m.round, t1.name as team1_name, t2.name as team2_name, m.team1_id, m.team2_id, w.name as winner_name + FROM matches m + LEFT JOIN teams t1 ON m.team1_id = t1.id + LEFT JOIN teams t2 ON m.team2_id = t2.id + LEFT JOIN teams w ON m.winner_id = w.id + WHERE m.tournament_id = ? + ORDER BY m.round, m.id +"); +$matchesStmt->execute([$tournamentId]); +$matches = $matchesStmt->fetchAll(); + +$rounds = []; +foreach ($matches as $match) { + $rounds[$match['round']][] = $match; +} + +?> + +

+ + + + +
+ +
+ + prepare("SELECT MAX(round) FROM matches WHERE tournament_id = ?"); + $stmt->execute([$tournamentId]); + $currentRound = $stmt->fetchColumn(); + + $stmt = db()->prepare("SELECT COUNT(*) FROM matches WHERE tournament_id = ? AND round = ? AND winner_id IS NULL"); + $stmt->execute([$tournamentId, $currentRound]); + $unfinishedMatches = $stmt->fetchColumn(); + + if ($unfinishedMatches == 0) { + $stmt = db()->prepare("SELECT COUNT(DISTINCT winner_id) FROM matches WHERE tournament_id = ? AND round = ?"); + $stmt->execute([$tournamentId, $currentRound]); + $distinctWinners = $stmt->fetchColumn(); + if ($distinctWinners > 1) { + echo '
'; + } else { + echo '
Winner: ' . $rounds[$currentRound][0]['winner_name'] . '
'; + } + } + ?> + + + +
+ $round_matches): ?> +
+
+
+

Round

+
+
    + +
  • +
    + + vs +
    + +

    Winner:

    + +
    + + +
    + + +
    +
  • + +
+
+
+ +
+ + + diff --git a/tournaments.php b/tournaments.php new file mode 100644 index 0000000..acbd728 --- /dev/null +++ b/tournaments.php @@ -0,0 +1,69 @@ +prepare("INSERT INTO tournaments (name) VALUES (?)"); + $stmt->execute([$tournamentName]); + $message = '
Tournament created successfully!
'; + } catch (PDOException $e) { + $message = '
Error: ' . $e->getMessage() . '
'; + } + } +} + +// Fetch all tournaments +$tournamentsStmt = db()->query("SELECT * FROM tournaments ORDER BY start_date DESC"); +$tournaments = $tournamentsStmt->fetchAll(); + +?> + +
+
+
+
+

Create New Tournament

+
+
+ +
+
+ + +
+ +
+
+
+
+
+
+
+

Existing Tournaments

+
+
+
    + 0): ?> + +
  • + + + +
  • + + +
  • No tournaments found.
  • + +
+
+
+
+
+ +