Skip to content
This repository was archived by the owner on Oct 15, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/php.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 33 additions & 13 deletions assets/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -359,20 +359,40 @@ ul.credit {
.app-overview-dashboard {
display: grid;
gap: 1rem;
grid-template:
"hello-text" auto
"announcements" auto
"weekly-metrics" auto
"historic-statistics" auto
"leaderboard" auto;

@media (min-width: 1440px) {

&-criterion-reference {
grid-template:
"hello-text" auto
"announcements" auto
"weekly-metrics" auto
"historic-statistics" auto
"leaderboard" auto;

@media (min-width: 1440px) {
grid-template:
"hello-text hello-text hello-text hello-text" auto
"announcements announcements announcements announcements" auto
"weekly-metrics weekly-metrics leaderboard leaderboard" 1fr
"historic-statistics historic-statistics leaderboard leaderboard" 1fr;
grid-template-columns: 2fr 2fr 1fr 1fr;
}
}

&-self-reference {
grid-template:
"hello-text hello-text hello-text hello-text" auto
"announcements announcements announcements announcements" auto
"weekly-metrics weekly-metrics leaderboard leaderboard" 1fr
"historic-statistics historic-statistics leaderboard leaderboard" 1fr;
grid-template-columns: 2fr 2fr 1fr 1fr;
"hello-text" auto
"announcements" auto
"weekly-metrics" auto
"historic-statistics" auto;

@media (min-width: 1440px) {
grid-template:
"hello-text hello-text hello-text hello-text" auto
"announcements announcements announcements announcements" auto
"weekly-metrics weekly-metrics weekly-metrics weekly-metrics" 1fr
"historic-statistics historic-statistics historic-statistics historic-statistics" 1fr;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
}

&__hello-text {
Expand Down
35 changes: 35 additions & 0 deletions migrations/Version20241230103024.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241230103024 extends AbstractMigration
{
public function getDescription(): string
{
return 'Layout for Overview';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL'
ALTER TABLE "group" ADD layout VARCHAR(255) DEFAULT NULL
SQL);
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL'
ALTER TABLE "group" DROP layout
SQL);
}
}
19 changes: 19 additions & 0 deletions src/Controller/Admin/GroupCrudController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@

use App\Entity\Group;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;

use function Symfony\Component\Translation\t;

class GroupCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
Expand All @@ -20,10 +23,26 @@ public static function getEntityFqcn(): string

public function configureFields(string $pageName): iterable
{
$availableLayouts = glob(__DIR__.'/../../../templates/overview/layout/*.html.twig');
if (false === $availableLayouts) {
$availableLayouts = [];
}

$availableLayouts = array_map(static fn ($path) => pathinfo($path, PATHINFO_BASENAME), $availableLayouts);
if (0 === \count($availableLayouts)) {
$availableLayouts = ['default.html.twig'];
}

// trim the .html.twig extension
$availableLayouts = array_map(static fn ($layout) => substr($layout, 0, -10), $availableLayouts);

return [
IdField::new('id')->hideOnForm(),
TextField::new('name', 'Name'),
TextEditorField::new('description', 'Description'),
ChoiceField::new('layout', 'Layout')
->setChoices(array_combine($availableLayouts, $availableLayouts))
->setHelp(t('admin.group.layout.help')),
DateTimeField::new('created_at', 'Created at')->hideOnForm(),
DateTimeField::new('updated_at', 'Updated at')->hideOnForm(),
];
Expand Down
2 changes: 1 addition & 1 deletion src/Controller/Admin/UserCrudController.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function configureFields(string $pageName): iterable
AssociationField::new('group', 'Group'),
DateTimeField::new('created_at', 'Created at')->hideOnForm(),
DateTimeField::new('updated_at', 'Updated at')->hideOnForm(),
DateTimeField::new('last_login_at', 'Last login at'),
DateTimeField::new('last_login_at', 'Last login at')->hideOnForm(),
];
}

Expand Down
11 changes: 9 additions & 2 deletions src/Controller/OverviewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@

namespace App\Controller;

use App\Entity\User;
use App\Repository\AnnouncementRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;

class OverviewController extends AbstractController
{
#[Route('/overview', name: 'app_overview')]
public function index(): Response
public function index(#[CurrentUser] User $user): Response
{
return $this->render('overview/index.html.twig');
$layoutName = $user->getGroup()?->getLayout() ?? 'default';
$mainContent = $this->renderView("overview/layout/{$layoutName}.html.twig");

return $this->render('overview/index.html.twig', [
'mainContent' => $mainContent,
]);
}

#[Route('/overview/announcements', name: 'app_overview_announcements')]
Expand Down
15 changes: 15 additions & 0 deletions src/Entity/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class Group
#[ORM\OneToMany(targetEntity: User::class, mappedBy: 'group')]
private Collection $users;

#[ORM\Column(length: 255, nullable: true)]
private ?string $layout = null;

public function __construct()
{
$this->users = new ArrayCollection();
Expand Down Expand Up @@ -109,4 +112,16 @@ public function removeUser(User $user): static

return $this;
}

public function getLayout(): ?string
{
return $this->layout;
}

public function setLayout(?string $layout): static
{
$this->layout = $layout;

return $this;
}
}
50 changes: 1 addition & 49 deletions templates/overview/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,5 @@
{% block title %}學習概況{% endblock %}

{% block app %}
<main class="app-overview-dashboard">
<section class="app-overview-dashboard__hello-text">
<h2 class="display-4">哈囉,{{ app.user.name }} 👋</h2>
<p class="lead">這些是你最近的表現 ↓</p>
</section>

<section class="app-overview-dashboard__announcements">
<turbo-frame id="announcements" class="app-overview-dashboard__hello-text" src="{{ path('app_overview_announcements') }}"></turbo-frame>
</section>

<section class="app-overview-dashboard__weekly-metrics">
<h3 class="mb-3">每週學習概況</h3>

<div class="row g-3">
<div class="col-12 col-md-6">
<div class="vstack gap-1">
<turbo-frame id="solved_questions" src="{{ path('app_overview_cards_solved_questions') }}"></turbo-frame>
<turbo-frame id="points" src="{{ path('app_overview_cards_points') }}"></turbo-frame>
<turbo-frame id="level" src="{{ path('app_overview_cards_level') }}"></turbo-frame>
</div>
</div>
<div class="col-12 col-md-6">
<turbo-frame id="events_daily_chart" src="{{ path('app_overview_cards_events_daily_chart') }}"></turbo-frame>
</div>
</div>
</section>

<section class="app-overview-dashboard__historic-statistics">
<h3 class="mb-3">學習歷程</h3>

<div class="row g-5">
<div class="col-12 col-md-6">
<div class="vstack gap-1">
<turbo-frame id="solved_questions" src="{{ path('app_overview_cards_solved_questions') }}"></turbo-frame>
<turbo-frame id="events_count" src="{{ path('app_overview_cards_events_count') }}"></turbo-frame>
<turbo-frame id="questions_count" src="{{ path('app_overview_cards_questions_count') }}"></turbo-frame>
</div>
</div>
<div class="col-12 col-md-6">
<turbo-frame id="events_history" src="{{ path('app_overview_cards_events_history') }}"></turbo-frame>
</div>
</div>
</section>

<section class="app-overview-dashboard__leaderboard">
<h3 class="mb-3">週排行榜</h3>
<turbo-frame id="leaderboard" src="{{ path('app_overview_cards_leaderboard') }}"></turbo-frame>
</section>
</main>
{{ mainContent|raw }}
{% endblock %}
49 changes: 49 additions & 0 deletions templates/overview/layout/default.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<main class="app-overview-dashboard app-overview-dashboard-criterion-reference">
<section class="app-overview-dashboard__hello-text">
<h2 class="display-4">哈囉,{{ app.user.name }} 👋</h2>
<p class="lead">這些是你最近的表現 ↓</p>
</section>

<section class="app-overview-dashboard__announcements">
<turbo-frame id="announcements" class="app-overview-dashboard__hello-text" src="{{ path('app_overview_announcements') }}"></turbo-frame>
</section>

<section class="app-overview-dashboard__weekly-metrics">
<h3 class="mb-3">每週學習概況</h3>

<div class="row g-3">
<div class="col-12 col-md-6">
<div class="vstack gap-1">
<turbo-frame id="solved_questions" src="{{ path('app_overview_cards_solved_questions') }}"></turbo-frame>
<turbo-frame id="points" src="{{ path('app_overview_cards_points') }}"></turbo-frame>
<turbo-frame id="level" src="{{ path('app_overview_cards_level') }}"></turbo-frame>
</div>
</div>
<div class="col-12 col-md-6">
<turbo-frame id="events_daily_chart" src="{{ path('app_overview_cards_events_daily_chart') }}"></turbo-frame>
</div>
</div>
</section>

<section class="app-overview-dashboard__historic-statistics">
<h3 class="mb-3">學習歷程</h3>

<div class="row g-5">
<div class="col-12 col-md-6">
<div class="vstack gap-1">
<turbo-frame id="solved_questions" src="{{ path('app_overview_cards_solved_questions') }}"></turbo-frame>
<turbo-frame id="events_count" src="{{ path('app_overview_cards_events_count') }}"></turbo-frame>
<turbo-frame id="questions_count" src="{{ path('app_overview_cards_questions_count') }}"></turbo-frame>
</div>
</div>
<div class="col-12 col-md-6">
<turbo-frame id="events_history" src="{{ path('app_overview_cards_events_history') }}"></turbo-frame>
</div>
</div>
</section>

<section class="app-overview-dashboard__leaderboard">
<h3 class="mb-3">週排行榜</h3>
<turbo-frame id="leaderboard" src="{{ path('app_overview_cards_leaderboard') }}"></turbo-frame>
</section>
</main>
44 changes: 44 additions & 0 deletions templates/overview/layout/self-reference.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<main class="app-overview-dashboard app-overview-dashboard-self-reference">
<section class="app-overview-dashboard__hello-text">
<h2 class="display-4">哈囉,{{ app.user.name }} 👋</h2>
<p class="lead">這些是你最近的表現 ↓</p>
</section>

<section class="app-overview-dashboard__announcements">
<turbo-frame id="announcements" class="app-overview-dashboard__hello-text" src="{{ path('app_overview_announcements') }}"></turbo-frame>
</section>

<section class="app-overview-dashboard__weekly-metrics">
<h3 class="mb-3">每週學習概況</h3>

<div class="row g-3">
<div class="col-12 col-md-6">
<div class="vstack gap-1">
<turbo-frame id="solved_questions" src="{{ path('app_overview_cards_solved_questions') }}"></turbo-frame>
<turbo-frame id="points" src="{{ path('app_overview_cards_points') }}"></turbo-frame>
<turbo-frame id="level" src="{{ path('app_overview_cards_level') }}"></turbo-frame>
</div>
</div>
<div class="col-12 col-md-6">
<turbo-frame id="events_daily_chart" src="{{ path('app_overview_cards_events_daily_chart') }}"></turbo-frame>
</div>
</div>
</section>

<section class="app-overview-dashboard__historic-statistics">
<h3 class="mb-3">學習歷程</h3>

<div class="row g-5">
<div class="col-12 col-md-6">
<div class="vstack gap-1">
<turbo-frame id="solved_questions" src="{{ path('app_overview_cards_solved_questions') }}"></turbo-frame>
<turbo-frame id="events_count" src="{{ path('app_overview_cards_events_count') }}"></turbo-frame>
<turbo-frame id="questions_count" src="{{ path('app_overview_cards_questions_count') }}"></turbo-frame>
</div>
</div>
<div class="col-12 col-md-6">
<turbo-frame id="events_history" src="{{ path('app_overview_cards_events_history') }}"></turbo-frame>
</div>
</div>
</section>
</main>
7 changes: 7 additions & 0 deletions translations/messages.en_US.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@ challenge:
column-different: The column names differ; please compare and modify according to the correct answer.
row-different: The %row% row you answered is different from the correct answer.
row-unmatched: The number of returned rows does not match the correct answer (the correct answer has %expected% rows, while you answered %actual% rows).

admin:
group:
layout:
help: >-
Layout name. Leave blank to use the default layout.
You can create your own layout in the <code>templates/overview/layout</code> directory in the code.
8 changes: 8 additions & 0 deletions translations/messages.zh_TW.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Last login at: 最後登入時間
Statistics: 統計資料
Completed Questions: 完成題數
Experience Points: 經驗值
Layout: 佈局

result_presenter.tabs.result: 執行結果
result_presenter.tabs.answer: 正確答案
Expand Down Expand Up @@ -191,3 +192,10 @@ email-kind:
transactional: 通知型信件
marketing: 行銷型信件
test: 測試用信件

admin:
group:
layout:
help: >-
版面名稱。留空代表使用預設版面。
可以在程式碼的 <code>templates/overview/layout</code> 目錄製作自己想要的版面。
Loading