浏览代码

first commit

父节点
当前提交
3bc0a688b4
共有 100 个文件被更改,包括 4289 次插入6 次删除
  1. 96
    0
      app/Filament/Resources/BadgeResource.php
  2. 17
    0
      app/Filament/Resources/BadgeResource/Pages/CreateBadge.php
  3. 17
    0
      app/Filament/Resources/BadgeResource/Pages/EditBadge.php
  4. 19
    0
      app/Filament/Resources/BadgeResource/Pages/ListBadges.php
  5. 102
    0
      app/Filament/Resources/BannerResource.php
  6. 17
    0
      app/Filament/Resources/BannerResource/Pages/CreateBanner.php
  7. 17
    0
      app/Filament/Resources/BannerResource/Pages/EditBanner.php
  8. 19
    0
      app/Filament/Resources/BannerResource/Pages/ListBanners.php
  9. 126
    0
      app/Filament/Resources/HistoryResource.php
  10. 17
    0
      app/Filament/Resources/HistoryResource/Pages/CreateHistory.php
  11. 24
    0
      app/Filament/Resources/HistoryResource/Pages/EditHistory.php
  12. 19
    0
      app/Filament/Resources/HistoryResource/Pages/ListHistories.php
  13. 80
    0
      app/Filament/Resources/NewsCategoryResource.php
  14. 17
    0
      app/Filament/Resources/NewsCategoryResource/Pages/CreateNewsCategory.php
  15. 17
    0
      app/Filament/Resources/NewsCategoryResource/Pages/EditNewsCategory.php
  16. 19
    0
      app/Filament/Resources/NewsCategoryResource/Pages/ListNewsCategories.php
  17. 286
    0
      app/Filament/Resources/NewsResource.php
  18. 17
    0
      app/Filament/Resources/NewsResource/Pages/CreateNews.php
  19. 17
    0
      app/Filament/Resources/NewsResource/Pages/EditNews.php
  20. 19
    0
      app/Filament/Resources/NewsResource/Pages/ListNews.php
  21. 96
    0
      app/Filament/Resources/ProfilePartResource.php
  22. 17
    0
      app/Filament/Resources/ProfilePartResource/Pages/CreateProfilePart.php
  23. 17
    0
      app/Filament/Resources/ProfilePartResource/Pages/EditProfilePart.php
  24. 19
    0
      app/Filament/Resources/ProfilePartResource/Pages/ListProfileParts.php
  25. 158
    0
      app/Filament/Resources/ProjectResource.php
  26. 17
    0
      app/Filament/Resources/ProjectResource/Pages/CreateProject.php
  27. 17
    0
      app/Filament/Resources/ProjectResource/Pages/EditProject.php
  28. 19
    0
      app/Filament/Resources/ProjectResource/Pages/ListProjects.php
  29. 79
    0
      app/Filament/Resources/RegionResource.php
  30. 17
    0
      app/Filament/Resources/RegionResource/Pages/CreateRegion.php
  31. 17
    0
      app/Filament/Resources/RegionResource/Pages/EditRegion.php
  32. 19
    0
      app/Filament/Resources/RegionResource/Pages/ListRegions.php
  33. 80
    0
      app/Filament/Resources/TagResource.php
  34. 17
    0
      app/Filament/Resources/TagResource/Pages/CreateTag.php
  35. 17
    0
      app/Filament/Resources/TagResource/Pages/EditTag.php
  36. 19
    0
      app/Filament/Resources/TagResource/Pages/ListTags.php
  37. 30
    0
      app/Models/Badge.php
  38. 10
    0
      app/Models/Badgeable.php
  39. 28
    0
      app/Models/Banner.php
  40. 26
    0
      app/Models/History.php
  41. 62
    0
      app/Models/News.php
  42. 23
    0
      app/Models/NewsCategory.php
  43. 59
    0
      app/Models/NewsParagraph.php
  44. 28
    0
      app/Models/NewsParagraphPhoto.php
  45. 26
    0
      app/Models/ProfilePart.php
  46. 40
    0
      app/Models/Project.php
  47. 15
    0
      app/Models/ProjectHistory.php
  48. 15
    0
      app/Models/ProjectSpaceInfo.php
  49. 15
    0
      app/Models/ProjectSummary.php
  50. 19
    0
      app/Models/Region.php
  51. 19
    0
      app/Models/Tag.php
  52. 10
    0
      app/Models/Taggable.php
  53. 11
    1
      app/Providers/AppServiceProvider.php
  54. 3
    2
      app/Providers/Filament/AdminPanelProvider.php
  55. 6
    1
      composer.json
  56. 533
    1
      composer.lock
  57. 92
    0
      config/filament-shield.php
  58. 101
    0
      config/filament.php
  59. 1
    1
      config/filesystems.php
  60. 160
    0
      config/livewire.php
  61. 33
    0
      database/migrations/2025_09_04_072958_create_banners_table.php
  62. 35
    0
      database/migrations/2025_09_04_073017_create_histories_table.php
  63. 34
    0
      database/migrations/2025_09_04_073235_create_profile_parts_table.php
  64. 31
    0
      database/migrations/2025_09_04_073459_create_news_categories_table.php
  65. 45
    0
      database/migrations/2025_09_04_073524_create_news_table.php
  66. 33
    0
      database/migrations/2025_09_17_033657_create_news_paragraphs_table.php
  67. 30
    0
      database/migrations/2025_09_17_033730_create_tags_table.php
  68. 32
    0
      database/migrations/2025_09_17_033900_create_badges_table.php
  69. 34
    0
      database/migrations/2025_09_18_033227_create_news_paragraph_photos_table.php
  70. 38
    0
      database/migrations/2025_09_18_091406_create_projects_table.php
  71. 31
    0
      database/migrations/2025_09_18_092245_create_regions_table.php
  72. 32
    0
      database/migrations/2025_09_18_092318_create_project_histories_table.php
  73. 37
    0
      database/migrations/2025_09_18_092430_create_project_summaries_table.php
  74. 31
    0
      database/migrations/2025_09_18_093917_create_taggables_table.php
  75. 31
    0
      database/migrations/2025_09_18_093938_create_badgeables_table.php
  76. 35
    0
      database/migrations/2025_09_19_111819_create_project_space_infos_table.php
  77. 12
    0
      lang/vendor/filament-panels/ar/global-search.php
  78. 63
    0
      lang/vendor/filament-panels/ar/layout.php
  79. 51
    0
      lang/vendor/filament-panels/ar/pages/auth/edit-profile.php
  80. 35
    0
      lang/vendor/filament-panels/ar/pages/auth/email-verification/email-verification-prompt.php
  81. 61
    0
      lang/vendor/filament-panels/ar/pages/auth/login.php
  82. 44
    0
      lang/vendor/filament-panels/ar/pages/auth/password-reset/request-password-reset.php
  83. 43
    0
      lang/vendor/filament-panels/ar/pages/auth/password-reset/reset-password.php
  84. 56
    0
      lang/vendor/filament-panels/ar/pages/auth/register.php
  85. 33
    0
      lang/vendor/filament-panels/ar/pages/dashboard.php
  86. 25
    0
      lang/vendor/filament-panels/ar/pages/tenancy/edit-tenant-profile.php
  87. 37
    0
      lang/vendor/filament-panels/ar/resources/pages/create-record.php
  88. 41
    0
      lang/vendor/filament-panels/ar/resources/pages/edit-record.php
  89. 7
    0
      lang/vendor/filament-panels/ar/resources/pages/list-records.php
  90. 17
    0
      lang/vendor/filament-panels/ar/resources/pages/view-record.php
  91. 7
    0
      lang/vendor/filament-panels/ar/unsaved-changes-alert.php
  92. 15
    0
      lang/vendor/filament-panels/ar/widgets/account-widget.php
  93. 17
    0
      lang/vendor/filament-panels/ar/widgets/filament-info-widget.php
  94. 12
    0
      lang/vendor/filament-panels/az/global-search.php
  95. 63
    0
      lang/vendor/filament-panels/az/layout.php
  96. 51
    0
      lang/vendor/filament-panels/az/pages/auth/edit-profile.php
  97. 35
    0
      lang/vendor/filament-panels/az/pages/auth/email-verification/email-verification-prompt.php
  98. 61
    0
      lang/vendor/filament-panels/az/pages/auth/login.php
  99. 42
    0
      lang/vendor/filament-panels/az/pages/auth/password-reset/request-password-reset.php
  100. 0
    0
      lang/vendor/filament-panels/az/pages/auth/password-reset/reset-password.php

+ 96
- 0
app/Filament/Resources/BadgeResource.php 查看文件

@@ -0,0 +1,96 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use AbdulmajeedJamaan\FilamentTranslatableTabs\TranslatableTabs;
6
+use App\Filament\Resources\BadgeResource\Pages;
7
+use App\Filament\Resources\BadgeResource\RelationManagers;
8
+use App\Models\Badge;
9
+use Filament\Forms;
10
+use Filament\Forms\Components\FileUpload;
11
+use Filament\Forms\Components\Group;
12
+use Filament\Forms\Components\Radio;
13
+use Filament\Forms\Components\Section;
14
+use Filament\Forms\Components\TextInput;
15
+use Filament\Forms\Form;
16
+use Filament\Resources\Resource;
17
+use Filament\Tables;
18
+use Filament\Tables\Columns\ImageColumn;
19
+use Filament\Tables\Columns\TextColumn;
20
+use Filament\Tables\Columns\TextInputColumn;
21
+use Filament\Tables\Table;
22
+use Illuminate\Database\Eloquent\Builder;
23
+use Illuminate\Database\Eloquent\SoftDeletingScope;
24
+
25
+class BadgeResource extends Resource
26
+{
27
+    protected static ?string $model = Badge::class;
28
+
29
+    protected static ?string $navigationIcon = 'heroicon-o-check-badge';
30
+    protected static ?string $navigationGroup = '其他設定';
31
+    protected static ?string $navigationLabel = "認證標章管理";
32
+    protected static ?string $modelLabel = "認證標章管理";
33
+
34
+    // 預設排序
35
+    protected static function booted()
36
+    {
37
+        static::addGlobalScope('ordered', function ($query) {
38
+            $query->orderBy('order')->orderBy('id');
39
+        });
40
+    }
41
+
42
+    public static function form(Form $form): Form
43
+    {
44
+        return $form
45
+            ->schema([
46
+                Section::make("")->schema([
47
+                    Group::make()->schema([
48
+                        TextInput::make("title")->label("徽章標題")->translatableTabs()->columnSpanFull(),
49
+                        Group::make()->schema([
50
+                            FileUpload::make("img_url")->label("圖片")->directory("badge")->columnSpan(1),
51
+                            TextInput::make("img_alt")->label("圖片註釋")->translatableTabs()->columnSpan(1)
52
+                        ])->columnSpanFull(),
53
+                        Radio::make("visible")->label("顯示/不顯示")->options([1 => "顯示", 0 => "不顯示"])->inline()->default(1)
54
+                        ->columnSpan(2)
55
+                    ])->columns(4)->columnSpanFull(),
56
+                ])
57
+            ]);
58
+    }
59
+
60
+    public static function table(Table $table): Table
61
+    {
62
+        return $table
63
+            ->columns([
64
+                //
65
+                TextColumn::make("title")->label("徽章標題"),
66
+                ImageColumn::make('img_url')->label("圖片")
67
+            ])
68
+            ->filters([
69
+                //
70
+            ])
71
+            ->actions([
72
+                Tables\Actions\EditAction::make(),
73
+            ])
74
+            ->bulkActions([
75
+                Tables\Actions\BulkActionGroup::make([
76
+                    Tables\Actions\DeleteBulkAction::make(),
77
+                ]),
78
+            ]);
79
+    }
80
+
81
+    public static function getRelations(): array
82
+    {
83
+        return [
84
+            //
85
+        ];
86
+    }
87
+
88
+    public static function getPages(): array
89
+    {
90
+        return [
91
+            'index' => Pages\ListBadges::route('/'),
92
+            'create' => Pages\CreateBadge::route('/create'),
93
+            'edit' => Pages\EditBadge::route('/{record}/edit'),
94
+        ];
95
+    }
96
+}

+ 17
- 0
app/Filament/Resources/BadgeResource/Pages/CreateBadge.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\BadgeResource\Pages;
4
+
5
+use App\Filament\Resources\BadgeResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateBadge extends CreateRecord
10
+{
11
+    protected static string $resource = BadgeResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 17
- 0
app/Filament/Resources/BadgeResource/Pages/EditBadge.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\BadgeResource\Pages;
4
+
5
+use App\Filament\Resources\BadgeResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditBadge extends EditRecord
10
+{
11
+    protected static string $resource = BadgeResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 19
- 0
app/Filament/Resources/BadgeResource/Pages/ListBadges.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\BadgeResource\Pages;
4
+
5
+use App\Filament\Resources\BadgeResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListBadges extends ListRecords
10
+{
11
+    protected static string $resource = BadgeResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 102
- 0
app/Filament/Resources/BannerResource.php 查看文件

@@ -0,0 +1,102 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use AbdulmajeedJamaan\FilamentTranslatableTabs\TranslatableTabs;
6
+use App\Filament\Resources\BannerResource\Pages;
7
+use App\Filament\Resources\BannerResource\RelationManagers;
8
+use App\Models\Banner;
9
+use Filament\Forms;
10
+use Filament\Forms\Components\FileUpload;
11
+use Filament\Forms\Components\Group;
12
+use Filament\Forms\Components\Radio;
13
+use Filament\Forms\Components\Section;
14
+use Filament\Forms\Components\Textarea;
15
+use Filament\Forms\Components\TextInput;
16
+use Filament\Forms\Form;
17
+use Filament\Resources\Resource;
18
+use Filament\Tables;
19
+use Filament\Tables\Columns\ImageColumn;
20
+use Filament\Tables\Table;
21
+use Illuminate\Database\Eloquent\Builder;
22
+use Illuminate\Database\Eloquent\SoftDeletingScope;
23
+
24
+class BannerResource extends Resource
25
+{
26
+    protected static ?string $model = Banner::class;
27
+    protected static ?string $modelLabel = "Banner";
28
+    protected static ?int $navigationSort = 1;
29
+
30
+    protected static ?string $navigationIcon = 'heroicon-o-photo';
31
+    // protected static ?string $navigationGroup = '上稿內容管理';
32
+    protected static ?string $navigationLabel = "首頁 Banner 管理";
33
+
34
+    // 預設排序
35
+    protected static function booted()
36
+    {
37
+        static::addGlobalScope('ordered', function ($query) {
38
+            $query->orderBy('order')->orderBy('id');
39
+        });
40
+    }
41
+
42
+    public static function form(Form $form): Form
43
+    {
44
+        return $form
45
+            ->schema([
46
+                //
47
+                Section::make("")->schema([
48
+                    Group::make()->schema([
49
+                        TranslatableTabs::make('')
50
+                        ->schema([
51
+                            Textarea::make("title")->label("大字標題"),
52
+                            Textarea::make("content")->label("小字標題")
53
+                        ])->columnSpanFull(),
54
+                        Group::make()->schema([
55
+                            FileUpload::make("img_url")->label("圖片")
56
+                            ->directory("banners")
57
+                            ->columnSpan(1),
58
+                            TextInput::make("img_alt")->label("圖片註釋")
59
+                            ->translatableTabs()->columnSpan(1)
60
+                        ])->columnSpanFull(),
61
+                        Radio::make("visible")->label("顯示/不顯示")->options([1 => "顯示", 0 => "不顯示"])->inline()->default(1)->columnSpan(2)
62
+                    ])->columns(4)->columnSpanFull(),
63
+                ])
64
+            ]);
65
+    }
66
+
67
+    public static function table(Table $table): Table
68
+    {
69
+        return $table
70
+            ->columns([
71
+                //
72
+                ImageColumn::make('img_url')->label("圖片")
73
+            ])
74
+            ->filters([
75
+                //
76
+            ])
77
+            ->actions([
78
+                Tables\Actions\EditAction::make(),
79
+            ])
80
+            ->bulkActions([
81
+                Tables\Actions\BulkActionGroup::make([
82
+                    Tables\Actions\DeleteBulkAction::make(),
83
+                ]),
84
+            ])->reorderable('order');
85
+    }
86
+
87
+    public static function getRelations(): array
88
+    {
89
+        return [
90
+            //
91
+        ];
92
+    }
93
+
94
+    public static function getPages(): array
95
+    {
96
+        return [
97
+            'index' => Pages\ListBanners::route('/'),
98
+            'create' => Pages\CreateBanner::route('/create'),
99
+            'edit' => Pages\EditBanner::route('/{record}/edit'),
100
+        ];
101
+    }
102
+}

+ 17
- 0
app/Filament/Resources/BannerResource/Pages/CreateBanner.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\BannerResource\Pages;
4
+
5
+use App\Filament\Resources\BannerResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateBanner extends CreateRecord
10
+{
11
+    protected static string $resource = BannerResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 17
- 0
app/Filament/Resources/BannerResource/Pages/EditBanner.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\BannerResource\Pages;
4
+
5
+use App\Filament\Resources\BannerResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditBanner extends EditRecord
10
+{
11
+    protected static string $resource = BannerResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 19
- 0
app/Filament/Resources/BannerResource/Pages/ListBanners.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\BannerResource\Pages;
4
+
5
+use App\Filament\Resources\BannerResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListBanners extends ListRecords
10
+{
11
+    protected static string $resource = BannerResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 126
- 0
app/Filament/Resources/HistoryResource.php 查看文件

@@ -0,0 +1,126 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use App\Filament\Resources\HistoryResource\Pages;
6
+use App\Filament\Resources\HistoryResource\RelationManagers;
7
+use App\Models\History;
8
+use Filament\Forms;
9
+use Filament\Forms\Components\FileUpload;
10
+use Filament\Forms\Components\Group;
11
+use Filament\Forms\Components\Radio;
12
+use Filament\Forms\Components\Section;
13
+use Filament\Forms\Components\Select;
14
+use Filament\Forms\Components\TextInput;
15
+use Filament\Forms\Form;
16
+use Filament\Resources\Resource;
17
+use Filament\Tables;
18
+use Filament\Tables\Columns\ImageColumn;
19
+use Filament\Tables\Columns\TextColumn;
20
+use Filament\Tables\Filters\SelectFilter;
21
+use Filament\Tables\Table;
22
+use Illuminate\Database\Eloquent\Builder;
23
+use Illuminate\Database\Eloquent\SoftDeletingScope;
24
+
25
+class HistoryResource extends Resource
26
+{
27
+    protected static ?string $model = History::class;
28
+
29
+    protected static ?string $navigationIcon = 'heroicon-o-list-bullet';
30
+    protected static ?string $navigationLabel = "宏匯里程管理";
31
+    protected static ?string $navigationGroup = '關於宏匯';
32
+    protected static ?string $modelLabel = "宏匯里程管理";
33
+
34
+    public static function form(Form $form): Form
35
+    {
36
+        return $form
37
+            ->schema([
38
+                Section::make("")->schema([
39
+                    Select::make("selected_year")->label("年份")->options(function () {
40
+                        $currentYear = now()->year;
41
+                        $years = [];
42
+                        // 從 10 年前到 5 年後
43
+                        for ($i = $currentYear - 10; $i <= $currentYear; $i++) {
44
+                            $years[$i] = strval($i) . '年';
45
+                        }
46
+
47
+                        return $years;
48
+                    })->columnSpan(1),
49
+                    Select::make("selected_month")->label("月份")->options(function (){
50
+                        $months = [];
51
+                        for($i=1;$i<=12 ;$i++){
52
+                            $months[$i] = strval($i) . "月";
53
+                        }
54
+                        return $months;
55
+                    })->default(now()->month)->columnSpan(1),
56
+                    TextInput::make("title")->label("標題")->translatableTabs()->columnSpanFull(),
57
+                    Group::make()->schema([
58
+                        FileUpload::make("img_url")->label("圖片")->directory("histories")
59
+                        ->columnSpanFull(),
60
+                        TextInput::make("img_alt")->label("圖片註釋")->translatableTabs()->columnSpanFull()
61
+                    ])->columnSpanFull(),
62
+                    Radio::make("visible")->label("顯示/不顯示")->options([1 => "顯示", 0 => "不顯示"])->inline()->default(1)->columnSpan(2)
63
+                ])->columns(3)
64
+            ]);
65
+    }
66
+
67
+    public static function table(Table $table): Table
68
+    {
69
+        return $table
70
+            ->columns([
71
+                TextColumn::make("selected_year")->label("年份")->alignCenter(),
72
+                TextColumn::make("selected_month")->label("月份")->alignCenter(),
73
+                TextColumn::make("title")->label("標題"),
74
+                ImageColumn::make("img_url")->alignCenter(),
75
+                TextColumn::make('created_at')->label("建立時間")->date(),
76
+                TextColumn::make('updated_at')->label("更新時間")->date(),
77
+            ])
78
+            ->filters([
79
+                SelectFilter::make('selected_year')->label("年份")
80
+                ->options(function () {
81
+                    $currentYear = now()->year;
82
+                    $years = [];
83
+                    // 從 10 年前到 5 年後
84
+                    for ($i = $currentYear - 10; $i <= $currentYear + 10; $i++) {
85
+                        $years[$i] = strval($i) . '年';
86
+                    }
87
+
88
+                    return $years;
89
+                })
90
+                ->attribute('selected_year'),
91
+                SelectFilter::make('selected_month')->label("月份")
92
+                ->options(function () {
93
+                    $months = [];
94
+                    for($i=1;$i<=12 ;$i++){
95
+                        $months[$i] = strval($i) . "月";
96
+                    }
97
+                    return $months;
98
+                })
99
+                ->attribute('selected_month'),
100
+            ])
101
+            ->actions([
102
+                Tables\Actions\EditAction::make(),
103
+            ])
104
+            ->bulkActions([
105
+                Tables\Actions\BulkActionGroup::make([
106
+                    Tables\Actions\DeleteBulkAction::make(),
107
+                ]),
108
+            ]);
109
+    }
110
+
111
+    public static function getRelations(): array
112
+    {
113
+        return [
114
+            //
115
+        ];
116
+    }
117
+
118
+    public static function getPages(): array
119
+    {
120
+        return [
121
+            'index' => Pages\ListHistories::route('/'),
122
+            'create' => Pages\CreateHistory::route('/create'),
123
+            'edit' => Pages\EditHistory::route('/{record}/edit'),
124
+        ];
125
+    }
126
+}

+ 17
- 0
app/Filament/Resources/HistoryResource/Pages/CreateHistory.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\HistoryResource\Pages;
4
+
5
+use App\Filament\Resources\HistoryResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateHistory extends CreateRecord
10
+{
11
+    protected static string $resource = HistoryResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 24
- 0
app/Filament/Resources/HistoryResource/Pages/EditHistory.php 查看文件

@@ -0,0 +1,24 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\HistoryResource\Pages;
4
+
5
+use App\Filament\Resources\HistoryResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditHistory extends EditRecord
10
+{
11
+    protected static string $resource = HistoryResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+
18
+    protected function getHeaderActions(): array
19
+    {
20
+        return [
21
+            Actions\DeleteAction::make(),
22
+        ];
23
+    }
24
+}

+ 19
- 0
app/Filament/Resources/HistoryResource/Pages/ListHistories.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\HistoryResource\Pages;
4
+
5
+use App\Filament\Resources\HistoryResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListHistories extends ListRecords
10
+{
11
+    protected static string $resource = HistoryResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 80
- 0
app/Filament/Resources/NewsCategoryResource.php 查看文件

@@ -0,0 +1,80 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use App\Filament\Resources\NewsCategoryResource\Pages;
6
+use App\Filament\Resources\NewsCategoryResource\RelationManagers;
7
+use App\Models\NewsCategory;
8
+use Filament\Forms;
9
+use Filament\Forms\Components\Group;
10
+use Filament\Forms\Components\Radio;
11
+use Filament\Forms\Components\Section;
12
+use Filament\Forms\Components\TextInput;
13
+use Filament\Forms\Form;
14
+use Filament\Resources\Resource;
15
+use Filament\Tables;
16
+use Filament\Tables\Columns\TextColumn;
17
+use Filament\Tables\Table;
18
+use Illuminate\Database\Eloquent\Builder;
19
+use Illuminate\Database\Eloquent\SoftDeletingScope;
20
+
21
+class NewsCategoryResource extends Resource
22
+{
23
+    protected static ?string $model = NewsCategory::class;
24
+
25
+    protected static ?string $navigationIcon = 'heroicon-o-newspaper';
26
+    protected static ?string $navigationLabel = "最新消息分類管理";
27
+    protected static ?string $navigationGroup = '最新消息';
28
+    protected static ?string $modelLabel = "最新消息分類管理";
29
+    protected static ?int $navigationSort = 3;
30
+
31
+    public static function form(Form $form): Form
32
+    {
33
+        return $form
34
+            ->schema([
35
+                Section::make("")->schema([
36
+                    Group::make()->schema([
37
+                        TextInput::make("name")->label("標題")->translatableTabs()->columnSpanFull(),
38
+                        Radio::make("visible")->label("顯示/不顯示")->options([1 => "顯示", 0 => "不顯示"])->inline()->default(1)
39
+                        ->columnSpan(2)
40
+                    ])->columns(4)->columnSpanFull()
41
+                ])
42
+            ]);
43
+    }
44
+
45
+    public static function table(Table $table): Table
46
+    {
47
+        return $table
48
+            ->columns([
49
+                TextColumn::make("name")->label("分類名稱"),
50
+                TextColumn::make("visible_str")->label("顯示/不顯示")
51
+            ])
52
+            ->filters([
53
+                //
54
+            ])
55
+            ->actions([
56
+                Tables\Actions\EditAction::make(),
57
+            ])
58
+            ->bulkActions([
59
+                Tables\Actions\BulkActionGroup::make([
60
+                    Tables\Actions\DeleteBulkAction::make(),
61
+                ]),
62
+            ]);
63
+    }
64
+
65
+    public static function getRelations(): array
66
+    {
67
+        return [
68
+            //
69
+        ];
70
+    }
71
+
72
+    public static function getPages(): array
73
+    {
74
+        return [
75
+            'index' => Pages\ListNewsCategories::route('/'),
76
+            'create' => Pages\CreateNewsCategory::route('/create'),
77
+            'edit' => Pages\EditNewsCategory::route('/{record}/edit'),
78
+        ];
79
+    }
80
+}

+ 17
- 0
app/Filament/Resources/NewsCategoryResource/Pages/CreateNewsCategory.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\NewsCategoryResource\Pages;
4
+
5
+use App\Filament\Resources\NewsCategoryResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateNewsCategory extends CreateRecord
10
+{
11
+    protected static string $resource = NewsCategoryResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 17
- 0
app/Filament/Resources/NewsCategoryResource/Pages/EditNewsCategory.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\NewsCategoryResource\Pages;
4
+
5
+use App\Filament\Resources\NewsCategoryResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditNewsCategory extends EditRecord
10
+{
11
+    protected static string $resource = NewsCategoryResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 19
- 0
app/Filament/Resources/NewsCategoryResource/Pages/ListNewsCategories.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\NewsCategoryResource\Pages;
4
+
5
+use App\Filament\Resources\NewsCategoryResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListNewsCategories extends ListRecords
10
+{
11
+    protected static string $resource = NewsCategoryResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 286
- 0
app/Filament/Resources/NewsResource.php 查看文件

@@ -0,0 +1,286 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use AbdulmajeedJamaan\FilamentTranslatableTabs\TranslatableTabs;
6
+use App\Filament\Resources\NewsResource\Pages;
7
+use App\Filament\Resources\NewsResource\RelationManagers;
8
+use App\Models\News;
9
+use App\Models\NewsCategory;
10
+use Filament\Forms;
11
+use Filament\Forms\Components\DatePicker;
12
+use Filament\Forms\Components\FileUpload;
13
+use Filament\Forms\Components\Group;
14
+use Filament\Forms\Components\Radio;
15
+use Filament\Forms\Components\Repeater;
16
+use Filament\Forms\Components\Section;
17
+use Filament\Forms\Components\Select;
18
+use Filament\Forms\Components\Tabs;
19
+use Filament\Forms\Components\Tabs\Tab;
20
+use Filament\Forms\Components\Textarea;
21
+use Filament\Forms\Components\TextInput;
22
+use Filament\Forms\Form;
23
+use Filament\Forms\Get;
24
+use Filament\Resources\Resource;
25
+use Filament\Tables;
26
+use Filament\Tables\Columns\IconColumn;
27
+use Filament\Tables\Columns\ImageColumn;
28
+use Filament\Tables\Columns\TextColumn;
29
+use Filament\Tables\Filters\SelectFilter;
30
+use Filament\Tables\Table;
31
+use Illuminate\Database\Eloquent\Builder;
32
+use Illuminate\Database\Eloquent\SoftDeletingScope;
33
+use Illuminate\Support\Str;
34
+use Malzariey\FilamentLexicalEditor\Enums\ToolbarItem;
35
+use Malzariey\FilamentLexicalEditor\FilamentLexicalEditor;
36
+
37
+class NewsResource extends Resource
38
+{
39
+    protected static ?string $model = News::class;
40
+
41
+    protected static ?string $navigationIcon = 'heroicon-o-newspaper';
42
+    protected static ?string $navigationLabel = "最新消息管理";
43
+    protected static ?string $navigationGroup = '最新消息';
44
+    protected static ?string $modelLabel = "最新消息管理";
45
+    protected static ?int $navigationSort = 3;
46
+
47
+    public static function form(Form $form): Form
48
+    {
49
+        $editor_toolbar= [
50
+            ToolbarItem::UNDO, ToolbarItem::REDO, ToolbarItem::NORMAL,
51
+            ToolbarItem::H2, ToolbarItem::H3, ToolbarItem::H4, ToolbarItem::H5,
52
+            ToolbarItem::BULLET, ToolbarItem::NUMBERED, ToolbarItem::FONT_SIZE,
53
+            ToolbarItem::BOLD, ToolbarItem::ITALIC, ToolbarItem::UNDERLINE,
54
+            ToolbarItem::LINK, ToolbarItem::TEXT_COLOR, ToolbarItem::BACKGROUND_COLOR,
55
+            ToolbarItem::SUBSCRIPT, ToolbarItem::LOWERCASE, ToolbarItem::DIVIDER,
56
+            ToolbarItem::UPPERCASE, ToolbarItem::CLEAR, ToolbarItem::HR
57
+        ];
58
+        return $form
59
+            ->schema([
60
+                //
61
+                Tabs::make()->schema([
62
+                    Tab::make("基本資訊")->schema([
63
+                        Select::make("news_category_id")->label("分類")->options(function (){
64
+                            return NewsCategory::pluck("name", "id");
65
+                        })->required()
66
+                        ->columnSpan(1),
67
+                        DatePicker::make("post_date")->label("發佈日")
68
+                        ->native(false)
69
+                        ->closeOnDateSelection()
70
+                        ->columnSpan(1),
71
+                        FileUpload::make("news_img")->label("圖片")
72
+                        ->directory("news")->maxSize(122880)
73
+                        ->columnSpan(2),
74
+                        TranslatableTabs::make('')
75
+                        ->schema([
76
+                            TextInput::make("title")
77
+                            ->label("標題")
78
+                            ->columnSpan(1),
79
+                            TextInput::make("written_by")
80
+                            ->label("撰文者")
81
+                            ->columnSpan(1),
82
+                            Textarea::make("description")
83
+                            ->label("簡述")
84
+                            ->columnSpan(2)
85
+                        ])->columns(2)->columnSpan(2),
86
+                    ])->columns(2),
87
+                    Tab::make("SEO")->schema([
88
+                        TranslatableTabs::make('')
89
+                        ->schema([
90
+                            TextInput::make("meta_title")->label("SEO 標題"),
91
+                            TextInput::make("meta_keyword")->label("SEO 關鍵字"),
92
+                            Textarea::make("meta_description")->label("SEO 簡述")
93
+                        ])->columnSpanFull(),
94
+                        FileUpload::make('meta_img')->label("放大預覽圖")
95
+                        ->directory("news/seo")
96
+                        ->columnSpan(1),
97
+                    ]),
98
+                    Tab::make("內文編輯")->schema([
99
+                        Repeater::make("paragraphs")->schema([
100
+                            TextInput::make('item_key')
101
+                                ->default(fn () => Str::random())
102
+                                ->hidden()
103
+                                ->afterStateHydrated(function (TextInput $component, $state) {
104
+                                    if (empty($state)) {
105
+                                        $component->state(Str::random());
106
+                                    }
107
+                                }),
108
+                            Radio::make("paragraph_type")->options([
109
+                                1 => "圖片",
110
+                                2 => "文字",
111
+                                // 3 => "影音"
112
+                            ])->label("")->inline()->default(1)->Live(),
113
+                            Group::make()->schema([
114
+                                Section::make('')->schema([
115
+                                    Repeater::make("multiple_images")->schema([
116
+                                        TextInput::make('para_img_item_key')
117
+                                            ->default(fn () => Str::random())
118
+                                            ->hidden()
119
+                                            ->afterStateHydrated(function (TextInput $component, $state) {
120
+                                                if (empty($state)) {
121
+                                                    $component->state(Str::random());
122
+                                                }
123
+                                            }),
124
+                                        TextInput::make("img_alt")->label("圖片註釋")->translatableTabs()->columnSpan(1),
125
+                                        FileUpload::make('img_url')->label("")
126
+                                        ->directory("news/paragraphs")
127
+                                        ->maxFiles(10),
128
+                                    ])
129
+                                    ->relationship("photos")
130
+                                    ->label("")
131
+                                    ->orderColumn('order')
132
+                                ])
133
+                            ])->visible(fn (Get $get):bool => $get("paragraph_type") == 1),
134
+                            Group::make()->schema([
135
+                                FilamentLexicalEditor::make('text_content_tw')
136
+                                    ->label('繁體中文內容')
137
+                                    ->id(fn ($get) => "text_content_tw_" . $get('item_key') . "_" . uniqid())
138
+                                    ->enabledToolbars($editor_toolbar)
139
+                                    ->columnSpanFull(),
140
+                                FilamentLexicalEditor::make('text_content_en')
141
+                                    ->label('English Content')
142
+                                    ->id(fn ($get) => "text_content_en_" . $get('item_key') . "_" . uniqid())
143
+                                    ->enabledToolbars($editor_toolbar)
144
+                                    ->columnSpanFull(),
145
+                            ])->visible(fn (Get $get):bool => $get("paragraph_type") == 2),
146
+                        ])
147
+                        ->mutateRelationshipDataBeforeFillUsing(function (array $data): array {
148
+
149
+                            if ($data['paragraph_type'] == 2 && !empty($data['text_content'])) {
150
+                                $content = is_string($data['text_content'])
151
+                                    ? json_decode($data['text_content'], true)
152
+                                    : $data['text_content'];
153
+
154
+                                if (is_array($content)) {
155
+                                    $data['text_content_tw'] = $content['zh_TW'] ?? '';
156
+                                    $data['text_content_en'] = $content['en'] ?? '';
157
+                                }
158
+                            }
159
+
160
+                            return $data;
161
+                        })
162
+                        ->mutateRelationshipDataBeforeSaveUsing(function (array $data): array{
163
+                            if ($data['paragraph_type'] == 2) {
164
+                                $data["text_content"] = ["zh_TW" => $data["text_content_tw"], "en" => $data["text_content_en"]];
165
+                                // 移除臨時的分離欄位,只保留合併的 JSON 欄位
166
+                                unset($data['text_content_tw']);
167
+                                unset($data['text_content_en']);
168
+                            }
169
+                            return $data;
170
+                        })
171
+                        ->relationship("paragraphs")
172
+                        ->label("段落")
173
+                        ->collapsible()
174
+                        ->reorderableWithButtons()
175
+                        ->orderColumn('order')
176
+                        ->cloneable()
177
+                    ])
178
+                ])->columnSpanFull(),
179
+            ]);
180
+    }
181
+
182
+    public static function table(Table $table): Table
183
+    {
184
+        return $table
185
+            ->columns([
186
+                //
187
+                TextColumn::make("newsCategory.name")->label("分類")->alignCenter(),
188
+                TextColumn::make("title")->label("標題")->alignCenter(),
189
+                TextColumn::make("written_by")->label("發佈者")->alignCenter(),
190
+                TextColumn::make("post_date")->label("發佈時間")->dateTime('Y/m/d')->alignCenter(),
191
+                ImageColumn::make("news_img_url")->label("列表圖")->alignCenter(),
192
+                TextColumn::make("list_audit_state")->label("狀態")->badge()
193
+                ->color(fn (string $state): string => match ($state) {
194
+                    '暫存' => 'warning',
195
+                    '已發佈' => 'success',
196
+                }),
197
+                IconColumn::make("on_top")->label("置頂")
198
+                ->color(fn (string $state): string => match ($state) {
199
+                    1 => 'success',
200
+                    default => ''
201
+                })
202
+                ->icon(fn (string $state): string => match ($state) {
203
+                    1 => 'heroicon-o-check-circle',
204
+                    default => ''
205
+                })
206
+                ->action(function ($record): void {
207
+                    $record->on_top = !$record->on_top;
208
+                    $record->save();
209
+                }),
210
+                TextColumn::make("created_at")->label("建立時間")->dateTime('Y/m/d H:i:s')->alignCenter(),
211
+                TextColumn::make("updated_at")->label("更新時間")->dateTime()->alignCenter(),
212
+            ])
213
+            ->filters([
214
+                SelectFilter::make('news_category_id')->label("分類")
215
+                ->options(NewsCategory::orderBy("order")->pluck("name", "id"))
216
+                ->attribute('news_category_id'),
217
+                SelectFilter::make('post_date')->label("年份")
218
+                ->options(News::select(\DB::raw("DATE_FORMAT(post_date, '%Y') as year"))->whereNotNull("post_date")->distinct()->pluck("year","year")->toArray())
219
+                ->query(
220
+                    fn (array $data, Builder $query): Builder =>
221
+                    $query->when(
222
+                        $data['value'],
223
+                        fn (Builder $query, $value): Builder => $query->where('post_date', 'like', $data['value']. "%")
224
+                    )
225
+                ),
226
+                SelectFilter::make('visible')->label("狀態")
227
+                ->options([
228
+                    0 => "暫存",
229
+                    1 => "已發佈",
230
+                ])
231
+                ->query(
232
+                    fn (array $data, Builder $query): Builder =>
233
+                    $query->when(
234
+                        $data['value'],
235
+                        fn (Builder $query, $value): Builder => $query->where('visible', $data['value'])
236
+                    )
237
+                ),
238
+            ])
239
+            ->actions([
240
+                Tables\Actions\EditAction::make(),
241
+                Tables\Actions\DeleteAction::make(),
242
+                \Filament\Tables\Actions\Action::make("audit")
243
+                ->label(fn ($record) => match ($record->visible) {
244
+                    0 => '發佈',
245
+                    1 => '下架',
246
+                })
247
+                ->color(fn ($record) => match ($record->visible) {
248
+                    0 => 'warning',
249
+                    1 => 'gray',
250
+                })
251
+                ->icon(fn ($record) => match ($record->visible) {
252
+                    0 => 'heroicon-m-chevron-double-up',
253
+                    1 => 'heroicon-m-chevron-double-down',
254
+                })
255
+                ->action(function ($record): void {
256
+                    $record->visible = !$record->visible;
257
+                    $record->save();
258
+                })
259
+                ->outlined()
260
+                ->requiresConfirmation(),
261
+            ])
262
+            ->bulkActions([
263
+                Tables\Actions\BulkActionGroup::make([
264
+                    Tables\Actions\DeleteBulkAction::make(),
265
+                ]),
266
+            ])
267
+            ->defaultSort('order', 'desc')
268
+            ->defaultSort('created_at', 'desc');
269
+    }
270
+
271
+    public static function getRelations(): array
272
+    {
273
+        return [
274
+            //
275
+        ];
276
+    }
277
+
278
+    public static function getPages(): array
279
+    {
280
+        return [
281
+            'index' => Pages\ListNews::route('/'),
282
+            'create' => Pages\CreateNews::route('/create'),
283
+            'edit' => Pages\EditNews::route('/{record}/edit'),
284
+        ];
285
+    }
286
+}

+ 17
- 0
app/Filament/Resources/NewsResource/Pages/CreateNews.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\NewsResource\Pages;
4
+
5
+use App\Filament\Resources\NewsResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateNews extends CreateRecord
10
+{
11
+    protected static string $resource = NewsResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 17
- 0
app/Filament/Resources/NewsResource/Pages/EditNews.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\NewsResource\Pages;
4
+
5
+use App\Filament\Resources\NewsResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditNews extends EditRecord
10
+{
11
+    protected static string $resource = NewsResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 19
- 0
app/Filament/Resources/NewsResource/Pages/ListNews.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\NewsResource\Pages;
4
+
5
+use App\Filament\Resources\NewsResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListNews extends ListRecords
10
+{
11
+    protected static string $resource = NewsResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 96
- 0
app/Filament/Resources/ProfilePartResource.php 查看文件

@@ -0,0 +1,96 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use AbdulmajeedJamaan\FilamentTranslatableTabs\TranslatableTabs;
6
+use App\Filament\Resources\ProfilePartResource\Pages;
7
+use App\Filament\Resources\ProfilePartResource\RelationManagers;
8
+use App\Models\ProfilePart;
9
+use Filament\Forms;
10
+use Filament\Forms\Components\FileUpload;
11
+use Filament\Forms\Components\Group;
12
+use Filament\Forms\Components\Section;
13
+use Filament\Forms\Components\Textarea;
14
+use Filament\Forms\Components\TextInput;
15
+use Filament\Forms\Form;
16
+use Filament\Resources\Resource;
17
+use Filament\Tables;
18
+use Filament\Tables\Columns\ImageColumn;
19
+use Filament\Tables\Columns\TextColumn;
20
+use Filament\Tables\Table;
21
+use Illuminate\Database\Eloquent\Builder;
22
+
23
+class ProfilePartResource extends Resource
24
+{
25
+    protected static ?string $model = ProfilePart::class;
26
+
27
+    protected static ?string $navigationIcon = 'heroicon-o-document';
28
+    protected static ?string $navigationLabel = "宏匯簡介管理";
29
+    protected static ?string $navigationGroup = '關於宏匯';
30
+    protected static ?string $modelLabel = "宏匯簡介管理";
31
+    protected static ?int $navigationSort = 2;
32
+
33
+    // 預設排序
34
+    protected static function booted()
35
+    {
36
+        static::addGlobalScope('ordered', function ($query) {
37
+            $query->orderBy('order')->orderBy('id');
38
+        });
39
+    }
40
+
41
+    public static function form(Form $form): Form
42
+    {
43
+        return $form
44
+            ->schema([
45
+                Section::make("")->schema([
46
+                    TranslatableTabs::make('')
47
+                    ->schema([
48
+                        TextInput::make("title")->label("標題")->columnSpanFull(),
49
+                        Textarea::make("content")->label("內文")->columnSpanFull()
50
+                    ])->columnSpanFull(),
51
+                    Group::make()->schema([
52
+                        FileUpload::make("img_url")->label("圖片")
53
+                        ->directory("profile-parts")
54
+                        ->columnSpanFull(),
55
+                        TextInput::make("img_alt")->label("圖片註釋")->translatableTabs()->columnSpanFull()
56
+                    ])->columnSpanFull(),
57
+                ])->columns(3)
58
+            ]);
59
+    }
60
+
61
+    public static function table(Table $table): Table
62
+    {
63
+        return $table
64
+            ->columns([
65
+                TextColumn::make("title")->label("標題"),
66
+                ImageColumn::make("img_url")->alignCenter(),
67
+            ])
68
+            ->filters([
69
+                //
70
+            ])
71
+            ->actions([
72
+                Tables\Actions\EditAction::make(),
73
+            ])
74
+            ->bulkActions([
75
+                Tables\Actions\BulkActionGroup::make([
76
+                    Tables\Actions\DeleteBulkAction::make(),
77
+                ]),
78
+            ])->reorderable('order');
79
+    }
80
+
81
+    public static function getRelations(): array
82
+    {
83
+        return [
84
+            //
85
+        ];
86
+    }
87
+
88
+    public static function getPages(): array
89
+    {
90
+        return [
91
+            'index' => Pages\ListProfileParts::route('/'),
92
+            'create' => Pages\CreateProfilePart::route('/create'),
93
+            'edit' => Pages\EditProfilePart::route('/{record}/edit'),
94
+        ];
95
+    }
96
+}

+ 17
- 0
app/Filament/Resources/ProfilePartResource/Pages/CreateProfilePart.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\ProfilePartResource\Pages;
4
+
5
+use App\Filament\Resources\ProfilePartResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateProfilePart extends CreateRecord
10
+{
11
+    protected static string $resource = ProfilePartResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 17
- 0
app/Filament/Resources/ProfilePartResource/Pages/EditProfilePart.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\ProfilePartResource\Pages;
4
+
5
+use App\Filament\Resources\ProfilePartResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditProfilePart extends EditRecord
10
+{
11
+    protected static string $resource = ProfilePartResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 19
- 0
app/Filament/Resources/ProfilePartResource/Pages/ListProfileParts.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\ProfilePartResource\Pages;
4
+
5
+use App\Filament\Resources\ProfilePartResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListProfileParts extends ListRecords
10
+{
11
+    protected static string $resource = ProfilePartResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 158
- 0
app/Filament/Resources/ProjectResource.php 查看文件

@@ -0,0 +1,158 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use AbdulmajeedJamaan\FilamentTranslatableTabs\TranslatableTabs;
6
+use App\Filament\Resources\ProjectResource\Pages;
7
+use App\Filament\Resources\ProjectResource\RelationManagers;
8
+use App\Models\Project;
9
+use App\Models\Region;
10
+use Filament\Forms;
11
+use Filament\Forms\Components\DatePicker;
12
+use Filament\Forms\Components\FileUpload;
13
+use Filament\Forms\Components\Group;
14
+use Filament\Forms\Components\Repeater;
15
+use Filament\Forms\Components\Section;
16
+use Filament\Forms\Components\Select;
17
+use Filament\Forms\Components\Tabs;
18
+use Filament\Forms\Components\Tabs\Tab;
19
+use Filament\Forms\Components\Textarea;
20
+use Filament\Forms\Components\TextInput;
21
+use Filament\Forms\Form;
22
+use Filament\Forms\Get;
23
+use Filament\Resources\Resource;
24
+use Filament\Tables;
25
+use Filament\Tables\Table;
26
+use Illuminate\Database\Eloquent\Builder;
27
+use Illuminate\Database\Eloquent\SoftDeletingScope;
28
+use Illuminate\Support\Facades\Storage;
29
+
30
+class ProjectResource extends Resource
31
+{
32
+    protected static ?string $model = Project::class;
33
+
34
+    protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
35
+    protected static ?string $navigationLabel = "專案項目管理";
36
+    protected static ?string $modelLabel = "專案項目管理";
37
+
38
+    public static function form(Form $form): Form
39
+    {
40
+        return $form
41
+            ->schema([
42
+                Section::make("")->schema([
43
+                    Select::make("region_id")->label("地區")->options(function (){
44
+                        return Region::where("visible",true)->pluck("name", "id");
45
+                    }),
46
+                    Select::make('tags')
47
+                        ->multiple()
48
+                        ->relationship('tags', 'name')
49
+                        ->preload()
50
+                        ->label('標籤'),
51
+                    TextInput::make("name")->label("項目名稱")->translatableTabs(),
52
+                    FileUpload::make("img_url")->label("圖片")->directory("project"),
53
+                    TextInput::make("img_alt")->label("圖片註釋")->translatableTabs(),
54
+                    Tabs::make()->tabs([
55
+                        Tab::make("專案概要")->schema([
56
+                            TranslatableTabs::make('')
57
+                                ->schema([
58
+                                    TextInput::make("address")->label("地址"),
59
+                                    Textarea::make("floor_plan")->label("樓層規劃"),
60
+                                    Textarea::make("building_structure")->label("建築結構"),
61
+                                    Textarea::make("design_unit")->label("設計團隊")
62
+                                ])
63
+                                ->columnSpanFull(),
64
+                            Select::make('badges')
65
+                                ->multiple()
66
+                                ->relationship('badges', 'title')
67
+                                ->getOptionLabelFromRecordUsing(function ($record) {
68
+                                    $imageHtml = $record->img_url
69
+                                        ? '<img src="' . Storage::url($record->img_url) . '" class="w-6 h-6 rounded-full mr-2 inline-block" />'
70
+                                        : '<div class="w-6 h-6 bg-gray-200 rounded-full mr-2 inline-block"></div>';
71
+
72
+                                    return new \Illuminate\Support\HtmlString($imageHtml . $record->title);
73
+                                })
74
+                                ->allowHtml()
75
+                                ->preload()
76
+                                ->label('取得標章')
77
+                                ->maxItems(8)
78
+                                ->required(),
79
+                            Repeater::make("summaries")->label("")->schema([
80
+                                TranslatableTabs::make('')
81
+                                ->schema([
82
+                                    TextInput::make("title")->label("標題")->columnSpanFull(),
83
+                                    Textarea::make("content")->label("內文")->columnSpanFull()
84
+                                ])->columnSpanFull(),
85
+                            ])
86
+                            ->relationship("summaries")
87
+                            ->label("")
88
+                            ->collapsible()
89
+                            ->reorderableWithButtons()
90
+                            ->orderColumn('order')
91
+                            ->cloneable(),
92
+                        ]),
93
+                        Tab::make("開發歷程")->schema([
94
+                            Repeater::make("histories")->label("")->schema([
95
+                                DatePicker::make("operate_date")->label("歷程日期")->columnSpan(1),
96
+                                TextInput::make("title")->label("標題")->translatableTabs()->columnSpanFull()
97
+                            ])
98
+                            ->relationship("histories", function ($query,Get $get, $livewire) {
99
+                                return $query->orderby("operate_date","desc");
100
+                            })
101
+                            ->collapsible()
102
+                            ->cloneable()
103
+                        ]),
104
+                        Tab::make("空間資訊")->schema([
105
+                            Repeater::make("spaceInfos")->label("")->schema([
106
+                                TranslatableTabs::make('')
107
+                                ->schema([
108
+                                    TextInput::make("title")->label("標題")->columnSpanFull(),
109
+                                    Textarea::make("content")->label("內文")->columnSpanFull()
110
+                                ])->columnSpanFull(),
111
+                            ])
112
+                            ->relationship("spaceInfos")
113
+                            ->label("")
114
+                            ->collapsible()
115
+                            ->reorderableWithButtons()
116
+                            ->orderColumn('order')
117
+                            ->cloneable(),
118
+                        ])
119
+                    ])
120
+                ]),
121
+            ]);
122
+    }
123
+
124
+    public static function table(Table $table): Table
125
+    {
126
+        return $table
127
+            ->columns([
128
+                //
129
+            ])
130
+            ->filters([
131
+                //
132
+            ])
133
+            ->actions([
134
+                Tables\Actions\EditAction::make(),
135
+            ])
136
+            ->bulkActions([
137
+                Tables\Actions\BulkActionGroup::make([
138
+                    Tables\Actions\DeleteBulkAction::make(),
139
+                ]),
140
+            ]);
141
+    }
142
+
143
+    public static function getRelations(): array
144
+    {
145
+        return [
146
+            //
147
+        ];
148
+    }
149
+
150
+    public static function getPages(): array
151
+    {
152
+        return [
153
+            'index' => Pages\ListProjects::route('/'),
154
+            'create' => Pages\CreateProject::route('/create'),
155
+            'edit' => Pages\EditProject::route('/{record}/edit'),
156
+        ];
157
+    }
158
+}

+ 17
- 0
app/Filament/Resources/ProjectResource/Pages/CreateProject.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\ProjectResource\Pages;
4
+
5
+use App\Filament\Resources\ProjectResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateProject extends CreateRecord
10
+{
11
+    protected static string $resource = ProjectResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 17
- 0
app/Filament/Resources/ProjectResource/Pages/EditProject.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\ProjectResource\Pages;
4
+
5
+use App\Filament\Resources\ProjectResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditProject extends EditRecord
10
+{
11
+    protected static string $resource = ProjectResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 19
- 0
app/Filament/Resources/ProjectResource/Pages/ListProjects.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\ProjectResource\Pages;
4
+
5
+use App\Filament\Resources\ProjectResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListProjects extends ListRecords
10
+{
11
+    protected static string $resource = ProjectResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 79
- 0
app/Filament/Resources/RegionResource.php 查看文件

@@ -0,0 +1,79 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use App\Filament\Resources\RegionResource\Pages;
6
+use App\Filament\Resources\RegionResource\RelationManagers;
7
+use App\Models\Region;
8
+use Filament\Forms;
9
+use Filament\Forms\Components\Group;
10
+use Filament\Forms\Components\Radio;
11
+use Filament\Forms\Components\Section;
12
+use Filament\Forms\Components\TextInput;
13
+use Filament\Forms\Form;
14
+use Filament\Resources\Resource;
15
+use Filament\Tables;
16
+use Filament\Tables\Columns\TextColumn;
17
+use Filament\Tables\Columns\TextInputColumn;
18
+use Filament\Tables\Table;
19
+use Illuminate\Database\Eloquent\Builder;
20
+use Illuminate\Database\Eloquent\SoftDeletingScope;
21
+
22
+class RegionResource extends Resource
23
+{
24
+    protected static ?string $model = Region::class;
25
+
26
+    protected static ?string $navigationIcon = 'heroicon-o-globe-americas';
27
+    protected static ?string $navigationGroup = '其他設定';
28
+    protected static ?string $navigationLabel = "區域管理";
29
+    protected static ?string $modelLabel = "區域管理";
30
+
31
+    public static function form(Form $form): Form
32
+    {
33
+        return $form
34
+            ->schema([
35
+                Section::make("")->schema([
36
+                    Group::make()->schema([
37
+                        TextInput::make("name")->label("名稱")->translatableTabs()->columnSpanFull(),
38
+                        Radio::make("visible")->label("顯示/不顯示")->options([1 => "顯示", 0 => "不顯示"])->inline()->default(1)
39
+                        ->columnSpan(2)
40
+                    ])->columns(4)->columnSpanFull()
41
+                ])
42
+            ]);
43
+    }
44
+
45
+    public static function table(Table $table): Table
46
+    {
47
+        return $table
48
+            ->columns([
49
+                TextColumn::make("name")->label("名稱")
50
+            ])
51
+            ->filters([
52
+                //
53
+            ])
54
+            ->actions([
55
+                Tables\Actions\EditAction::make(),
56
+            ])
57
+            ->bulkActions([
58
+                Tables\Actions\BulkActionGroup::make([
59
+                    Tables\Actions\DeleteBulkAction::make(),
60
+                ]),
61
+            ]);
62
+    }
63
+
64
+    public static function getRelations(): array
65
+    {
66
+        return [
67
+            //
68
+        ];
69
+    }
70
+
71
+    public static function getPages(): array
72
+    {
73
+        return [
74
+            'index' => Pages\ListRegions::route('/'),
75
+            'create' => Pages\CreateRegion::route('/create'),
76
+            'edit' => Pages\EditRegion::route('/{record}/edit'),
77
+        ];
78
+    }
79
+}

+ 17
- 0
app/Filament/Resources/RegionResource/Pages/CreateRegion.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\RegionResource\Pages;
4
+
5
+use App\Filament\Resources\RegionResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateRegion extends CreateRecord
10
+{
11
+    protected static string $resource = RegionResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 17
- 0
app/Filament/Resources/RegionResource/Pages/EditRegion.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\RegionResource\Pages;
4
+
5
+use App\Filament\Resources\RegionResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditRegion extends EditRecord
10
+{
11
+    protected static string $resource = RegionResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 19
- 0
app/Filament/Resources/RegionResource/Pages/ListRegions.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\RegionResource\Pages;
4
+
5
+use App\Filament\Resources\RegionResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListRegions extends ListRecords
10
+{
11
+    protected static string $resource = RegionResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 80
- 0
app/Filament/Resources/TagResource.php 查看文件

@@ -0,0 +1,80 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use App\Filament\Resources\TagResource\Pages;
6
+use App\Filament\Resources\TagResource\RelationManagers;
7
+use App\Models\Tag;
8
+use Filament\Forms;
9
+use Filament\Forms\Components\Group;
10
+use Filament\Forms\Components\Radio;
11
+use Filament\Forms\Components\Section;
12
+use Filament\Forms\Components\TextInput;
13
+use Filament\Forms\Form;
14
+use Filament\Resources\Resource;
15
+use Filament\Tables;
16
+use Filament\Tables\Columns\TextColumn;
17
+use Filament\Tables\Columns\TextInputColumn;
18
+use Filament\Tables\Table;
19
+use Illuminate\Database\Eloquent\Builder;
20
+use Illuminate\Database\Eloquent\SoftDeletingScope;
21
+
22
+class TagResource extends Resource
23
+{
24
+    protected static ?string $model = Tag::class;
25
+
26
+    protected static ?string $navigationIcon = 'heroicon-o-tag';
27
+    protected static ?string $navigationGroup = '其他設定';
28
+    protected static ?string $navigationLabel = "標籤管理";
29
+    protected static ?string $modelLabel = "標籤管理";
30
+
31
+    public static function form(Form $form): Form
32
+    {
33
+        return $form
34
+        ->schema([
35
+            Section::make("")->schema([
36
+                Group::make()->schema([
37
+                    TextInput::make("name")->label("標籤名稱")->translatableTabs()->columnSpanFull(),
38
+                    Radio::make("visible")->label("顯示/不顯示")->options([1 => "顯示", 0 => "不顯示"])->inline()->default(1)
39
+                    ->columnSpan(2)
40
+                ])->columns(4)->columnSpanFull()
41
+            ])
42
+        ]);
43
+    }
44
+
45
+    public static function table(Table $table): Table
46
+    {
47
+        return $table
48
+            ->columns([
49
+                //
50
+                TextColumn::make("name")->label("標籤名稱")
51
+            ])
52
+            ->filters([
53
+                //
54
+            ])
55
+            ->actions([
56
+                Tables\Actions\EditAction::make(),
57
+            ])
58
+            ->bulkActions([
59
+                Tables\Actions\BulkActionGroup::make([
60
+                    Tables\Actions\DeleteBulkAction::make(),
61
+                ]),
62
+            ]);
63
+    }
64
+
65
+    public static function getRelations(): array
66
+    {
67
+        return [
68
+            //
69
+        ];
70
+    }
71
+
72
+    public static function getPages(): array
73
+    {
74
+        return [
75
+            'index' => Pages\ListTags::route('/'),
76
+            'create' => Pages\CreateTag::route('/create'),
77
+            'edit' => Pages\EditTag::route('/{record}/edit'),
78
+        ];
79
+    }
80
+}

+ 17
- 0
app/Filament/Resources/TagResource/Pages/CreateTag.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\TagResource\Pages;
4
+
5
+use App\Filament\Resources\TagResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateTag extends CreateRecord
10
+{
11
+    protected static string $resource = TagResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 17
- 0
app/Filament/Resources/TagResource/Pages/EditTag.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\TagResource\Pages;
4
+
5
+use App\Filament\Resources\TagResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\EditRecord;
8
+
9
+class EditTag extends EditRecord
10
+{
11
+    protected static string $resource = TagResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+}

+ 19
- 0
app/Filament/Resources/TagResource/Pages/ListTags.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Filament\Resources\TagResource\Pages;
4
+
5
+use App\Filament\Resources\TagResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+
9
+class ListTags extends ListRecords
10
+{
11
+    protected static string $resource = TagResource::class;
12
+
13
+    protected function getHeaderActions(): array
14
+    {
15
+        return [
16
+            Actions\CreateAction::make()->label("新增"),
17
+        ];
18
+    }
19
+}

+ 30
- 0
app/Models/Badge.php 查看文件

@@ -0,0 +1,30 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Casts\Attribute;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Illuminate\Support\Facades\Storage;
8
+use Spatie\Translatable\HasTranslations;
9
+
10
+class Badge extends Model
11
+{
12
+    use HasTranslations;
13
+
14
+    protected $guarded = ["id"];
15
+    public $translatable = ["title", "img_alt"];
16
+    protected $appends = ["img_url_link"];
17
+
18
+    protected function imgUrlLink(): Attribute
19
+    {
20
+        return Attribute::make(
21
+            get: fn ($value) => is_null($this->ing_url) ? null :Storage::url($this->ing_url),
22
+        );
23
+    }
24
+
25
+    public function projects()
26
+    {
27
+        return $this->morphedByMany(Project::class, 'badgeable');
28
+    }
29
+
30
+}

+ 10
- 0
app/Models/Badgeable.php 查看文件

@@ -0,0 +1,10 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+
7
+class Badgeable extends Model
8
+{
9
+    //
10
+}

+ 28
- 0
app/Models/Banner.php 查看文件

@@ -0,0 +1,28 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Casts\Attribute;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Illuminate\Support\Facades\Storage;
8
+use Spatie\Translatable\HasTranslations;
9
+
10
+class Banner extends Model
11
+{
12
+    use HasTranslations;
13
+
14
+    //
15
+    protected $guarded  = ["id"];
16
+    public $translatable = ['title', 'content', 'img_alt'];
17
+
18
+    public $appends = [
19
+        "img_url_link"
20
+    ];
21
+
22
+    protected function imgUrlLink(): Attribute
23
+    {
24
+        return Attribute::make(
25
+            get: fn ($value) => is_null($this->ing_url) ? null :Storage::url($this->ing_url),
26
+        );
27
+    }
28
+}

+ 26
- 0
app/Models/History.php 查看文件

@@ -0,0 +1,26 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Casts\Attribute;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Illuminate\Support\Facades\Storage;
8
+use Spatie\Translatable\HasTranslations;
9
+
10
+class History extends Model
11
+{
12
+    use HasTranslations;
13
+    protected $guarded  = ["id"];
14
+    public $translatable = ['title', 'img_alt'];
15
+
16
+    public $appends = [
17
+        "img_url_link"
18
+    ];
19
+
20
+    protected function imgUrlLink(): Attribute
21
+    {
22
+        return Attribute::make(
23
+            get: fn ($value) => is_null($this->img_url) ? null :Storage::url($this->img_url),
24
+        );
25
+    }
26
+}

+ 62
- 0
app/Models/News.php 查看文件

@@ -0,0 +1,62 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Casts\Attribute;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Illuminate\Database\Eloquent\SoftDeletes;
8
+use Illuminate\Support\Facades\Storage;
9
+use Spatie\Translatable\HasTranslations;
10
+
11
+class News extends Model
12
+{
13
+    use HasTranslations, SoftDeletes;
14
+    protected $casts = [
15
+        'on_top' => 'boolean',
16
+        "list_audit_state" => "string",
17
+    ];
18
+    protected $guarded = ['id'];
19
+    protected $appends = ["news_img_url", "meta_img_url"];
20
+    public $translatable = ['title', 'written_by', 'description', 'meta_title', 'meta_description', 'meta_keyword'];
21
+
22
+    public function newsCategory(){
23
+        return $this->belongsTo(NewsCategory::class);
24
+    }
25
+
26
+    public function paragraphs(){
27
+        return $this->hasMany(NewsParagraph::class)->orderBy('order');
28
+    }
29
+    protected function newsImgUrl(): Attribute
30
+    {
31
+        return Attribute::make(
32
+            get: fn ($value) => is_null($this->news_imgc) ? null :Storage::url($this->news_img),
33
+        );
34
+    }
35
+
36
+    protected function metaImgUrl(): Attribute
37
+    {
38
+        return Attribute::make(
39
+            get: fn ($value) => is_null($this->meta_img) ? null :Storage::url($this->meta_img),
40
+        );
41
+    }
42
+
43
+    protected function listAuditState(): Attribute
44
+    {
45
+        return Attribute::make(
46
+            get: fn ($value) => $this->attributes["visible"] == 1 ? "已發佈" : "暫存",
47
+        );
48
+    }
49
+    protected static function booted()
50
+    {
51
+        static::saving(function ($news) {
52
+            // 如果正在將此記錄設為置頂
53
+            if ($news->isDirty('on_top') && $news->on_top == 1) {
54
+                // 將其他所有記錄的置頂狀態取消
55
+                static::where('id', '!=', $news->id)
56
+                    ->where('news_category_id', $news->news_category_id)
57
+                    ->where('on_top', 1)
58
+                    ->update(['on_top' => 0]);
59
+            }
60
+        });
61
+    }
62
+}

+ 23
- 0
app/Models/NewsCategory.php 查看文件

@@ -0,0 +1,23 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Casts\Attribute;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Illuminate\Database\Eloquent\SoftDeletes;
8
+use Spatie\Translatable\HasTranslations;
9
+
10
+class NewsCategory extends Model
11
+{
12
+    use HasTranslations; use SoftDeletes;
13
+    const VISIBLE_Y = "顯示";
14
+    const VISIBLE_N = "不顯示";
15
+    protected $guarded = ['id'];
16
+
17
+
18
+    public $translatable = ['name'];
19
+
20
+    public function news(){
21
+        return $this->hasMany(News::class);
22
+    }
23
+}

+ 59
- 0
app/Models/NewsParagraph.php 查看文件

@@ -0,0 +1,59 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+use Spatie\Translatable\HasTranslations;
7
+
8
+class NewsParagraph extends Model
9
+{
10
+    use HasTranslations;
11
+    CONST IMAGE = 1;
12
+    CONST TEXT = 2;
13
+
14
+    protected $guarded = ['id'];
15
+    public $timestamps = false;
16
+    protected $casts = [
17
+        'text_content' => 'array',         // JSON 轉陣列
18
+    ];
19
+
20
+    public function news(){
21
+        return $this->belongsTo(News::class);
22
+    }
23
+
24
+    public function contentType()
25
+    {
26
+        switch ($this->paragraph_type){
27
+            case 1:
28
+                return "image";
29
+            case 2:
30
+                return "text";
31
+            default:
32
+                return "";
33
+        }
34
+    }
35
+    public function photos(){
36
+        return $this->hasMany(NewsParagraphPhoto::class)->orderBy("order");
37
+    }
38
+    /**
39
+     * 取得特定語言的文字內容
40
+     */
41
+    public function getTextContent($locale = 'zh_TW'): string
42
+    {
43
+        if ($this->paragraph_type != 2) {
44
+            return '';
45
+        }
46
+
47
+        $content = $this->text_content;
48
+
49
+        if (is_array($content)) {
50
+            return $content[$locale] ?? '';
51
+        }
52
+
53
+        if (is_string($content)) {
54
+            $decoded = json_decode($content, true);
55
+            return $decoded[$locale] ?? '';
56
+        }
57
+        return '';
58
+    }
59
+}

+ 28
- 0
app/Models/NewsParagraphPhoto.php 查看文件

@@ -0,0 +1,28 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Casts\Attribute;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Illuminate\Support\Facades\Storage;
8
+use Spatie\Translatable\HasTranslations;
9
+
10
+class NewsParagraphPhoto extends Model
11
+{
12
+    use HasTranslations;
13
+
14
+    protected $guarded = ['id'];
15
+    public $timestamps = false;
16
+    protected $appends = ['photo_img_url'];
17
+    public $translatable = ['img_alt'];
18
+
19
+    public function paragraph(){
20
+        return $this->belongsTo(NewsParagraph::class);
21
+    }
22
+    protected function photoImgUrl(): Attribute
23
+    {
24
+        return Attribute::make(
25
+            get: fn ($value) => is_null($this->img_url) ? null :Storage::url($this->img_url),
26
+        );
27
+    }
28
+}

+ 26
- 0
app/Models/ProfilePart.php 查看文件

@@ -0,0 +1,26 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Casts\Attribute;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Illuminate\Support\Facades\Storage;
8
+use Spatie\Translatable\HasTranslations;
9
+
10
+class ProfilePart extends Model
11
+{
12
+    use HasTranslations;
13
+    protected $guarded  = ["id"];
14
+    public $translatable = ['title', 'content', 'img_alt'];
15
+
16
+    public $appends = [
17
+        "img_url_link"
18
+    ];
19
+
20
+    protected function imgUrlLink(): Attribute
21
+    {
22
+        return Attribute::make(
23
+            get: fn ($value) => is_null($this->ing_url) ? null :Storage::url($this->ing_url),
24
+        );
25
+    }
26
+}

+ 40
- 0
app/Models/Project.php 查看文件

@@ -0,0 +1,40 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+use Illuminate\Database\Eloquent\SoftDeletes;
7
+use Spatie\Translatable\HasTranslations;
8
+
9
+class Project extends Model
10
+{
11
+    use HasTranslations, SoftDeletes;
12
+    protected $guarded = ['id'];
13
+
14
+    protected $translatable = ["title"];
15
+
16
+    public function tags()
17
+    {
18
+        return $this->morphToMany(Tag::class, 'taggable');
19
+    }
20
+
21
+    public function badges()
22
+    {
23
+        return $this->morphToMany(Badge::class, 'badgeable');
24
+    }
25
+
26
+    public function histories()
27
+    {
28
+        return $this->hasMany(ProjectHistory::class);
29
+    }
30
+
31
+    public function summaries()
32
+    {
33
+        return $this->hasMany(ProjectSummary::class);
34
+    }
35
+
36
+    public function spaceInfos()
37
+    {
38
+        return $this->hasMany(ProjectSpaceInfo::class);
39
+    }
40
+}

+ 15
- 0
app/Models/ProjectHistory.php 查看文件

@@ -0,0 +1,15 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+use Illuminate\Database\Eloquent\SoftDeletes;
7
+use Spatie\Translatable\HasTranslations;
8
+
9
+class ProjectHistory extends Model
10
+{
11
+    //
12
+    use HasTranslations, SoftDeletes;
13
+    protected $guarded = ["id"];
14
+    protected $translatable = ["title", "img_alt"];
15
+}

+ 15
- 0
app/Models/ProjectSpaceInfo.php 查看文件

@@ -0,0 +1,15 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+use Illuminate\Database\Eloquent\SoftDeletes;
7
+use Spatie\Translatable\HasTranslations;
8
+
9
+class ProjectSpaceInfo extends Model
10
+{
11
+    //
12
+    use HasTranslations, SoftDeletes;
13
+    protected $guarded = ["id"];
14
+    protected $translatable = ["title", "content"];
15
+}

+ 15
- 0
app/Models/ProjectSummary.php 查看文件

@@ -0,0 +1,15 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+use Illuminate\Database\Eloquent\SoftDeletes;
7
+use Spatie\Translatable\HasTranslations;
8
+
9
+class ProjectSummary extends Model
10
+{
11
+    //
12
+    use HasTranslations, SoftDeletes;
13
+    protected $guarded = ["id"];
14
+    protected $translatable = ["title", "content"];
15
+}

+ 19
- 0
app/Models/Region.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+use Spatie\Translatable\HasTranslations;
7
+
8
+class Region extends Model
9
+{
10
+    use HasTranslations;
11
+
12
+    protected $guarded = ["id"];
13
+    public $translatable = ['name'];
14
+
15
+    public function projects()
16
+    {
17
+        return $this->hasMany(Project::class);
18
+    }
19
+}

+ 19
- 0
app/Models/Tag.php 查看文件

@@ -0,0 +1,19 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+use Spatie\Translatable\HasTranslations;
7
+
8
+class Tag extends Model
9
+{
10
+    use HasTranslations;
11
+
12
+    protected $guarded = ["id"];
13
+    public $translatable = ["name"];
14
+
15
+    public function projects()
16
+    {
17
+        return $this->morphedByMany(Project::class, 'taggable');
18
+    }
19
+}

+ 10
- 0
app/Models/Taggable.php 查看文件

@@ -0,0 +1,10 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+
7
+class Taggable extends Model
8
+{
9
+    //
10
+}

+ 11
- 1
app/Providers/AppServiceProvider.php 查看文件

@@ -2,6 +2,7 @@
2 2
 
3 3
 namespace App\Providers;
4 4
 
5
+use AbdulmajeedJamaan\FilamentTranslatableTabs\TranslatableTabs;
5 6
 use Illuminate\Support\ServiceProvider;
6 7
 
7 8
 class AppServiceProvider extends ServiceProvider
@@ -19,6 +20,15 @@ class AppServiceProvider extends ServiceProvider
19 20
      */
20 21
     public function boot(): void
21 22
     {
22
-        //
23
+        TranslatableTabs::configureUsing(function (TranslatableTabs $component) {
24
+            $component
25
+                // locales labels
26
+                ->localesLabels([
27
+                    'zh_TW' => __('中文'),
28
+                    'en' => __('英文')
29
+                ])
30
+                // default locales
31
+                ->locales(['zh_TW', 'en']);
32
+        });
23 33
     }
24 34
 }

+ 3
- 2
app/Providers/Filament/AdminPanelProvider.php 查看文件

@@ -10,6 +10,7 @@ use Filament\Pages;
10 10
 use Filament\Pages\Auth\Login;
11 11
 use Filament\Panel;
12 12
 use Filament\PanelProvider;
13
+use Filament\SpatieLaravelTranslatablePlugin;
13 14
 use Filament\Support\Colors\Color;
14 15
 use Filament\Widgets;
15 16
 use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
@@ -39,7 +40,6 @@ class AdminPanelProvider extends PanelProvider
39 40
             ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
40 41
             ->widgets([
41 42
                 Widgets\AccountWidget::class,
42
-                Widgets\FilamentInfoWidget::class,
43 43
             ])
44 44
             ->middleware([
45 45
                 EncryptCookies::class,
@@ -54,6 +54,7 @@ class AdminPanelProvider extends PanelProvider
54 54
             ])
55 55
             ->authMiddleware([
56 56
                 Authenticate::class,
57
-            ]);
57
+            ])
58
+            ->plugin(SpatieLaravelTranslatablePlugin::make()->defaultLocales(['zh_TW', 'en']));
58 59
     }
59 60
 }

+ 6
- 1
composer.json 查看文件

@@ -7,9 +7,14 @@
7 7
     "license": "MIT",
8 8
     "require": {
9 9
         "php": "^8.2",
10
+        "abdulmajeed-jamaan/filament-translatable-tabs": "^3.0",
11
+        "bezhansalleh/filament-shield": "^3.3",
10 12
         "filament/filament": "^3.3",
13
+        "filament/spatie-laravel-translatable-plugin": "^3.2",
11 14
         "laravel/framework": "^12.0",
12
-        "laravel/tinker": "^2.10.1"
15
+        "laravel/tinker": "^2.10.1",
16
+        "malzariey/filament-lexical-editor": "^1.1",
17
+        "novadaemon/filament-combobox": "^1.2"
13 18
     },
14 19
     "require-dev": {
15 20
         "fakerphp/faker": "^1.23",

+ 533
- 1
composer.lock 查看文件

@@ -4,9 +4,86 @@
4 4
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 5
         "This file is @generated automatically"
6 6
     ],
7
-    "content-hash": "e9195d18e64145f4dd264bfa14a2f846",
7
+    "content-hash": "23ce7a9a0a953b5acd4695907ed9b85d",
8 8
     "packages": [
9 9
         {
10
+            "name": "abdulmajeed-jamaan/filament-translatable-tabs",
11
+            "version": "v3.0.2",
12
+            "source": {
13
+                "type": "git",
14
+                "url": "https://github.com/Abdulmajeed-Jamaan/filament-translatable-tabs.git",
15
+                "reference": "541be8ab928f07c884861d18010084b57375e9f7"
16
+            },
17
+            "dist": {
18
+                "type": "zip",
19
+                "url": "https://api.github.com/repos/Abdulmajeed-Jamaan/filament-translatable-tabs/zipball/541be8ab928f07c884861d18010084b57375e9f7",
20
+                "reference": "541be8ab928f07c884861d18010084b57375e9f7",
21
+                "shasum": ""
22
+            },
23
+            "require": {
24
+                "filament/forms": "^3.0",
25
+                "php": "^8.1",
26
+                "spatie/laravel-package-tools": "^1.15.0"
27
+            },
28
+            "require-dev": {
29
+                "laravel/pint": "^1.0",
30
+                "nunomaduro/collision": "^7.9",
31
+                "nunomaduro/larastan": "^2.0.1",
32
+                "orchestra/testbench": "^8.0",
33
+                "pestphp/pest": "^2.1",
34
+                "pestphp/pest-plugin-arch": "^2.0",
35
+                "pestphp/pest-plugin-laravel": "^2.0",
36
+                "phpstan/extension-installer": "^1.1",
37
+                "phpstan/phpstan-deprecation-rules": "^1.0",
38
+                "phpstan/phpstan-phpunit": "^1.0"
39
+            },
40
+            "type": "library",
41
+            "extra": {
42
+                "laravel": {
43
+                    "aliases": [],
44
+                    "providers": [
45
+                        "AbdulmajeedJamaan\\FilamentTranslatableTabs\\FilamentTranslatableTabsServiceProvider"
46
+                    ]
47
+                }
48
+            },
49
+            "autoload": {
50
+                "psr-4": {
51
+                    "AbdulmajeedJamaan\\FilamentTranslatableTabs\\": "src/"
52
+                }
53
+            },
54
+            "notification-url": "https://packagist.org/downloads/",
55
+            "license": [
56
+                "MIT"
57
+            ],
58
+            "authors": [
59
+                {
60
+                    "name": "Abdulmajeed-Jamaan",
61
+                    "email": "abdulmajeed.jamaan@outlook.com",
62
+                    "role": "Developer"
63
+                }
64
+            ],
65
+            "description": "Simplifying managing json based translation columns using tabs",
66
+            "homepage": "https://github.com/abdulmajeed-jamaan/filament-translatable-tabs",
67
+            "keywords": [
68
+                "Abdulmajeed-Jamaan",
69
+                "filament",
70
+                "filament-translatable-tabs",
71
+                "laravel",
72
+                "translation"
73
+            ],
74
+            "support": {
75
+                "issues": "https://github.com/abdulmajeed-jamaan/filament-translatable-tabs/issues",
76
+                "source": "https://github.com/abdulmajeed-jamaan/filament-translatable-tabs"
77
+            },
78
+            "funding": [
79
+                {
80
+                    "url": "https://github.com/Abdulmajeed-Jamaan",
81
+                    "type": "github"
82
+                }
83
+            ],
84
+            "time": "2025-07-30T18:17:41+00:00"
85
+        },
86
+        {
10 87
             "name": "anourvalar/eloquent-serialize",
11 88
             "version": "1.3.4",
12 89
             "source": {
@@ -73,6 +150,93 @@
73 150
             "time": "2025-07-30T15:45:57+00:00"
74 151
         },
75 152
         {
153
+            "name": "bezhansalleh/filament-shield",
154
+            "version": "3.3.9",
155
+            "source": {
156
+                "type": "git",
157
+                "url": "https://github.com/bezhanSalleh/filament-shield.git",
158
+                "reference": "9cb6c3e9c6cdf49f41e984067f8fa2458c23d163"
159
+            },
160
+            "dist": {
161
+                "type": "zip",
162
+                "url": "https://api.github.com/repos/bezhanSalleh/filament-shield/zipball/9cb6c3e9c6cdf49f41e984067f8fa2458c23d163",
163
+                "reference": "9cb6c3e9c6cdf49f41e984067f8fa2458c23d163",
164
+                "shasum": ""
165
+            },
166
+            "require": {
167
+                "filament/filament": "^3.2",
168
+                "php": "^8.1",
169
+                "spatie/laravel-package-tools": "^1.9",
170
+                "spatie/laravel-permission": "^6.0"
171
+            },
172
+            "require-dev": {
173
+                "larastan/larastan": "^2.0",
174
+                "laravel/pint": "^1.0",
175
+                "nunomaduro/collision": "^7.0|^8.0",
176
+                "orchestra/testbench": "^8.0|^9.0",
177
+                "pestphp/pest": "^2.34",
178
+                "pestphp/pest-plugin-laravel": "^2.3",
179
+                "phpstan/extension-installer": "^1.3",
180
+                "phpstan/phpstan-deprecation-rules": "^1.1",
181
+                "phpstan/phpstan-phpunit": "^1.3",
182
+                "phpunit/phpunit": "^10.1",
183
+                "spatie/laravel-ray": "^1.37"
184
+            },
185
+            "type": "library",
186
+            "extra": {
187
+                "laravel": {
188
+                    "aliases": {
189
+                        "FilamentShield": "BezhanSalleh\\FilamentShield\\Facades\\FilamentShield"
190
+                    },
191
+                    "providers": [
192
+                        "BezhanSalleh\\FilamentShield\\FilamentShieldServiceProvider"
193
+                    ]
194
+                }
195
+            },
196
+            "autoload": {
197
+                "psr-4": {
198
+                    "BezhanSalleh\\FilamentShield\\": "src",
199
+                    "BezhanSalleh\\FilamentShield\\Database\\Factories\\": "database/factories"
200
+                }
201
+            },
202
+            "notification-url": "https://packagist.org/downloads/",
203
+            "license": [
204
+                "MIT"
205
+            ],
206
+            "authors": [
207
+                {
208
+                    "name": "Bezhan Salleh",
209
+                    "email": "bezhan_salleh@yahoo.com",
210
+                    "role": "Developer"
211
+                }
212
+            ],
213
+            "description": "Filament support for `spatie/laravel-permission`.",
214
+            "homepage": "https://github.com/bezhansalleh/filament-shield",
215
+            "keywords": [
216
+                "acl",
217
+                "bezhanSalleh",
218
+                "filament",
219
+                "filament-shield",
220
+                "laravel",
221
+                "permission",
222
+                "permissions",
223
+                "rbac",
224
+                "roles",
225
+                "security"
226
+            ],
227
+            "support": {
228
+                "issues": "https://github.com/bezhanSalleh/filament-shield/issues",
229
+                "source": "https://github.com/bezhanSalleh/filament-shield/tree/3.3.9"
230
+            },
231
+            "funding": [
232
+                {
233
+                    "url": "https://github.com/bezhanSalleh",
234
+                    "type": "github"
235
+                }
236
+            ],
237
+            "time": "2025-07-10T23:02:45+00:00"
238
+        },
239
+        {
76 240
             "name": "blade-ui-kit/blade-heroicons",
77 241
             "version": "2.6.0",
78 242
             "source": {
@@ -1262,6 +1426,51 @@
1262 1426
             "time": "2025-07-08T20:42:18+00:00"
1263 1427
         },
1264 1428
         {
1429
+            "name": "filament/spatie-laravel-translatable-plugin",
1430
+            "version": "v3.3.37",
1431
+            "source": {
1432
+                "type": "git",
1433
+                "url": "https://github.com/filamentphp/spatie-laravel-translatable-plugin.git",
1434
+                "reference": "7de417487ee7a4edd9e66fb3243a27f84db3f543"
1435
+            },
1436
+            "dist": {
1437
+                "type": "zip",
1438
+                "url": "https://api.github.com/repos/filamentphp/spatie-laravel-translatable-plugin/zipball/7de417487ee7a4edd9e66fb3243a27f84db3f543",
1439
+                "reference": "7de417487ee7a4edd9e66fb3243a27f84db3f543",
1440
+                "shasum": ""
1441
+            },
1442
+            "require": {
1443
+                "filament/support": "self.version",
1444
+                "illuminate/support": "^10.45|^11.0|^12.0",
1445
+                "php": "^8.1",
1446
+                "spatie/laravel-translatable": "^6.0"
1447
+            },
1448
+            "type": "library",
1449
+            "extra": {
1450
+                "laravel": {
1451
+                    "providers": [
1452
+                        "Filament\\SpatieLaravelTranslatablePluginServiceProvider"
1453
+                    ]
1454
+                }
1455
+            },
1456
+            "autoload": {
1457
+                "psr-4": {
1458
+                    "Filament\\": "src"
1459
+                }
1460
+            },
1461
+            "notification-url": "https://packagist.org/downloads/",
1462
+            "license": [
1463
+                "MIT"
1464
+            ],
1465
+            "description": "Filament support for `spatie/laravel-translatable`.",
1466
+            "homepage": "https://github.com/filamentphp/filament",
1467
+            "support": {
1468
+                "issues": "https://github.com/filamentphp/filament/issues",
1469
+                "source": "https://github.com/filamentphp/filament"
1470
+            },
1471
+            "time": "2025-08-12T13:15:45+00:00"
1472
+        },
1473
+        {
1265 1474
             "name": "filament/support",
1266 1475
             "version": "v3.3.37",
1267 1476
             "source": {
@@ -3147,6 +3356,81 @@
3147 3356
             "time": "2025-07-17T05:12:15+00:00"
3148 3357
         },
3149 3358
         {
3359
+            "name": "malzariey/filament-lexical-editor",
3360
+            "version": "1.1",
3361
+            "source": {
3362
+                "type": "git",
3363
+                "url": "https://github.com/malzariey/filament-lexical-editor.git",
3364
+                "reference": "df8d9ffcfc078fdafaa85a4265fdf03d835d5b27"
3365
+            },
3366
+            "dist": {
3367
+                "type": "zip",
3368
+                "url": "https://api.github.com/repos/malzariey/filament-lexical-editor/zipball/df8d9ffcfc078fdafaa85a4265fdf03d835d5b27",
3369
+                "reference": "df8d9ffcfc078fdafaa85a4265fdf03d835d5b27",
3370
+                "shasum": ""
3371
+            },
3372
+            "require": {
3373
+                "filament/filament": "^3.0",
3374
+                "filament/forms": "^3.0",
3375
+                "php": "^8.1",
3376
+                "spatie/laravel-package-tools": "^1.15.0"
3377
+            },
3378
+            "require-dev": {
3379
+                "nunomaduro/collision": "^7.9",
3380
+                "orchestra/testbench": "^8.0",
3381
+                "pestphp/pest": "^2.1",
3382
+                "pestphp/pest-plugin-arch": "^2.0",
3383
+                "pestphp/pest-plugin-laravel": "^2.0"
3384
+            },
3385
+            "type": "library",
3386
+            "extra": {
3387
+                "laravel": {
3388
+                    "providers": [
3389
+                        "Malzariey\\FilamentLexicalEditor\\FilamentLexicalEditorServiceProvider"
3390
+                    ]
3391
+                }
3392
+            },
3393
+            "autoload": {
3394
+                "psr-4": {
3395
+                    "Malzariey\\FilamentLexicalEditor\\": "src/"
3396
+                }
3397
+            },
3398
+            "notification-url": "https://packagist.org/downloads/",
3399
+            "license": [
3400
+                "MIT"
3401
+            ],
3402
+            "authors": [
3403
+                {
3404
+                    "name": "Majid Al Zariey",
3405
+                    "email": "malzariey@hajarco.com",
3406
+                    "role": "Developer"
3407
+                }
3408
+            ],
3409
+            "description": "Implementation of meta's lexical editor in FilamentPHP, a modern, extensible text editor framework.",
3410
+            "homepage": "https://github.com/malzariey/filament-lexical-editor",
3411
+            "keywords": [
3412
+                "Malzariey",
3413
+                "editor",
3414
+                "filaemntPHP",
3415
+                "filament-lexical-editor",
3416
+                "laravel",
3417
+                "lexical",
3418
+                "rich-text",
3419
+                "text-editor"
3420
+            ],
3421
+            "support": {
3422
+                "issues": "https://github.com/malzariey/filament-lexical-editor/issues",
3423
+                "source": "https://github.com/malzariey/filament-lexical-editor"
3424
+            },
3425
+            "funding": [
3426
+                {
3427
+                    "url": "https://github.com/malzariey",
3428
+                    "type": "github"
3429
+                }
3430
+            ],
3431
+            "time": "2025-04-30T11:06:41+00:00"
3432
+        },
3433
+        {
3150 3434
             "name": "masterminds/html5",
3151 3435
             "version": "2.10.0",
3152 3436
             "source": {
@@ -3631,6 +3915,88 @@
3631 3915
             "time": "2025-08-13T20:13:15+00:00"
3632 3916
         },
3633 3917
         {
3918
+            "name": "novadaemon/filament-combobox",
3919
+            "version": "v1.2.0",
3920
+            "source": {
3921
+                "type": "git",
3922
+                "url": "https://github.com/novadaemon/filament-combobox.git",
3923
+                "reference": "e8c99cb5a713cfd818c67eab6f6bc1fd9c8b0020"
3924
+            },
3925
+            "dist": {
3926
+                "type": "zip",
3927
+                "url": "https://api.github.com/repos/novadaemon/filament-combobox/zipball/e8c99cb5a713cfd818c67eab6f6bc1fd9c8b0020",
3928
+                "reference": "e8c99cb5a713cfd818c67eab6f6bc1fd9c8b0020",
3929
+                "shasum": ""
3930
+            },
3931
+            "require": {
3932
+                "filament/filament": "^3.0",
3933
+                "filament/forms": "^3.0",
3934
+                "php": "^8.1",
3935
+                "spatie/laravel-package-tools": "^1.15.0"
3936
+            },
3937
+            "require-dev": {
3938
+                "laravel/pint": "^1.0",
3939
+                "nunomaduro/collision": "^7.9",
3940
+                "nunomaduro/larastan": "^2.0.1",
3941
+                "orchestra/testbench": "^8.0",
3942
+                "pestphp/pest": "^2.1",
3943
+                "pestphp/pest-plugin-arch": "^2.0",
3944
+                "pestphp/pest-plugin-laravel": "^2.0",
3945
+                "phpstan/extension-installer": "^1.1",
3946
+                "phpstan/phpstan-deprecation-rules": "^1.0",
3947
+                "phpstan/phpstan-phpunit": "^1.0",
3948
+                "spatie/laravel-ray": "^1.26"
3949
+            },
3950
+            "type": "library",
3951
+            "extra": {
3952
+                "laravel": {
3953
+                    "providers": [
3954
+                        "Novadaemon\\FilamentCombobox\\FilamentComboboxServiceProvider"
3955
+                    ]
3956
+                }
3957
+            },
3958
+            "autoload": {
3959
+                "psr-4": {
3960
+                    "Novadaemon\\FilamentCombobox\\": "src/"
3961
+                }
3962
+            },
3963
+            "notification-url": "https://packagist.org/downloads/",
3964
+            "license": [
3965
+                "MIT"
3966
+            ],
3967
+            "authors": [
3968
+                {
3969
+                    "name": "Jesús García",
3970
+                    "email": "novadaemon@gmail.com",
3971
+                    "role": "Developer"
3972
+                }
3973
+            ],
3974
+            "description": "Side by side combobox multiselect field to use in your FilamentPHP forms",
3975
+            "homepage": "https://github.com/novadaemon/filament-combobox",
3976
+            "keywords": [
3977
+                "Combobox",
3978
+                "Forms",
3979
+                "field",
3980
+                "filament",
3981
+                "filament-combobox",
3982
+                "laravel",
3983
+                "multiple",
3984
+                "novadaemon",
3985
+                "select"
3986
+            ],
3987
+            "support": {
3988
+                "issues": "https://github.com/novadaemon/filament-combobox/issues",
3989
+                "source": "https://github.com/novadaemon/filament-combobox"
3990
+            },
3991
+            "funding": [
3992
+                {
3993
+                    "url": "https://github.com/novadaemon",
3994
+                    "type": "github"
3995
+                }
3996
+            ],
3997
+            "time": "2025-06-11T17:19:01+00:00"
3998
+        },
3999
+        {
3634 4000
             "name": "nunomaduro/termwind",
3635 4001
             "version": "v2.3.1",
3636 4002
             "source": {
@@ -4880,6 +5246,172 @@
4880 5246
             "time": "2025-07-17T15:46:43+00:00"
4881 5247
         },
4882 5248
         {
5249
+            "name": "spatie/laravel-permission",
5250
+            "version": "6.21.0",
5251
+            "source": {
5252
+                "type": "git",
5253
+                "url": "https://github.com/spatie/laravel-permission.git",
5254
+                "reference": "6a118e8855dfffcd90403aab77bbf35a03db51b3"
5255
+            },
5256
+            "dist": {
5257
+                "type": "zip",
5258
+                "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/6a118e8855dfffcd90403aab77bbf35a03db51b3",
5259
+                "reference": "6a118e8855dfffcd90403aab77bbf35a03db51b3",
5260
+                "shasum": ""
5261
+            },
5262
+            "require": {
5263
+                "illuminate/auth": "^8.12|^9.0|^10.0|^11.0|^12.0",
5264
+                "illuminate/container": "^8.12|^9.0|^10.0|^11.0|^12.0",
5265
+                "illuminate/contracts": "^8.12|^9.0|^10.0|^11.0|^12.0",
5266
+                "illuminate/database": "^8.12|^9.0|^10.0|^11.0|^12.0",
5267
+                "php": "^8.0"
5268
+            },
5269
+            "require-dev": {
5270
+                "laravel/passport": "^11.0|^12.0",
5271
+                "laravel/pint": "^1.0",
5272
+                "orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0",
5273
+                "phpunit/phpunit": "^9.4|^10.1|^11.5"
5274
+            },
5275
+            "type": "library",
5276
+            "extra": {
5277
+                "laravel": {
5278
+                    "providers": [
5279
+                        "Spatie\\Permission\\PermissionServiceProvider"
5280
+                    ]
5281
+                },
5282
+                "branch-alias": {
5283
+                    "dev-main": "6.x-dev",
5284
+                    "dev-master": "6.x-dev"
5285
+                }
5286
+            },
5287
+            "autoload": {
5288
+                "files": [
5289
+                    "src/helpers.php"
5290
+                ],
5291
+                "psr-4": {
5292
+                    "Spatie\\Permission\\": "src"
5293
+                }
5294
+            },
5295
+            "notification-url": "https://packagist.org/downloads/",
5296
+            "license": [
5297
+                "MIT"
5298
+            ],
5299
+            "authors": [
5300
+                {
5301
+                    "name": "Freek Van der Herten",
5302
+                    "email": "freek@spatie.be",
5303
+                    "homepage": "https://spatie.be",
5304
+                    "role": "Developer"
5305
+                }
5306
+            ],
5307
+            "description": "Permission handling for Laravel 8.0 and up",
5308
+            "homepage": "https://github.com/spatie/laravel-permission",
5309
+            "keywords": [
5310
+                "acl",
5311
+                "laravel",
5312
+                "permission",
5313
+                "permissions",
5314
+                "rbac",
5315
+                "roles",
5316
+                "security",
5317
+                "spatie"
5318
+            ],
5319
+            "support": {
5320
+                "issues": "https://github.com/spatie/laravel-permission/issues",
5321
+                "source": "https://github.com/spatie/laravel-permission/tree/6.21.0"
5322
+            },
5323
+            "funding": [
5324
+                {
5325
+                    "url": "https://github.com/spatie",
5326
+                    "type": "github"
5327
+                }
5328
+            ],
5329
+            "time": "2025-07-23T16:08:05+00:00"
5330
+        },
5331
+        {
5332
+            "name": "spatie/laravel-translatable",
5333
+            "version": "6.11.4",
5334
+            "source": {
5335
+                "type": "git",
5336
+                "url": "https://github.com/spatie/laravel-translatable.git",
5337
+                "reference": "032d85b28de315310dab2048b857016f1194f68b"
5338
+            },
5339
+            "dist": {
5340
+                "type": "zip",
5341
+                "url": "https://api.github.com/repos/spatie/laravel-translatable/zipball/032d85b28de315310dab2048b857016f1194f68b",
5342
+                "reference": "032d85b28de315310dab2048b857016f1194f68b",
5343
+                "shasum": ""
5344
+            },
5345
+            "require": {
5346
+                "illuminate/database": "^10.0|^11.0|^12.0",
5347
+                "illuminate/support": "^10.0|^11.0|^12.0",
5348
+                "php": "^8.0",
5349
+                "spatie/laravel-package-tools": "^1.11"
5350
+            },
5351
+            "require-dev": {
5352
+                "friendsofphp/php-cs-fixer": "^3.64",
5353
+                "mockery/mockery": "^1.4",
5354
+                "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
5355
+                "pestphp/pest": "^1.20|^2.0|^3.0"
5356
+            },
5357
+            "type": "library",
5358
+            "extra": {
5359
+                "aliases": {
5360
+                    "Translatable": "Spatie\\Translatable\\Facades\\Translatable"
5361
+                },
5362
+                "laravel": {
5363
+                    "providers": [
5364
+                        "Spatie\\Translatable\\TranslatableServiceProvider"
5365
+                    ]
5366
+                }
5367
+            },
5368
+            "autoload": {
5369
+                "psr-4": {
5370
+                    "Spatie\\Translatable\\": "src"
5371
+                }
5372
+            },
5373
+            "notification-url": "https://packagist.org/downloads/",
5374
+            "license": [
5375
+                "MIT"
5376
+            ],
5377
+            "authors": [
5378
+                {
5379
+                    "name": "Freek Van der Herten",
5380
+                    "email": "freek@spatie.be",
5381
+                    "homepage": "https://spatie.be",
5382
+                    "role": "Developer"
5383
+                },
5384
+                {
5385
+                    "name": "Sebastian De Deyne",
5386
+                    "email": "sebastian@spatie.be",
5387
+                    "homepage": "https://spatie.be",
5388
+                    "role": "Developer"
5389
+                }
5390
+            ],
5391
+            "description": "A trait to make an Eloquent model hold translations",
5392
+            "homepage": "https://github.com/spatie/laravel-translatable",
5393
+            "keywords": [
5394
+                "eloquent",
5395
+                "i8n",
5396
+                "laravel-translatable",
5397
+                "model",
5398
+                "multilingual",
5399
+                "spatie",
5400
+                "translate"
5401
+            ],
5402
+            "support": {
5403
+                "issues": "https://github.com/spatie/laravel-translatable/issues",
5404
+                "source": "https://github.com/spatie/laravel-translatable/tree/6.11.4"
5405
+            },
5406
+            "funding": [
5407
+                {
5408
+                    "url": "https://github.com/spatie",
5409
+                    "type": "github"
5410
+                }
5411
+            ],
5412
+            "time": "2025-02-20T15:51:22+00:00"
5413
+        },
5414
+        {
4883 5415
             "name": "symfony/clock",
4884 5416
             "version": "v7.3.0",
4885 5417
             "source": {

+ 92
- 0
config/filament-shield.php 查看文件

@@ -0,0 +1,92 @@
1
+<?php
2
+
3
+return [
4
+    'shield_resource' => [
5
+        'should_register_navigation' => true,
6
+        'slug' => 'shield/roles',
7
+        'navigation_sort' => -1,
8
+        'navigation_badge' => true,
9
+        'navigation_group' => true,
10
+        'sub_navigation_position' => null,
11
+        'is_globally_searchable' => false,
12
+        'show_model_path' => true,
13
+        'is_scoped_to_tenant' => true,
14
+        'cluster' => null,
15
+    ],
16
+
17
+    'tenant_model' => null,
18
+
19
+    'auth_provider_model' => [
20
+        'fqcn' => 'App\\Models\\User',
21
+    ],
22
+
23
+    'super_admin' => [
24
+        'enabled' => true,
25
+        'name' => 'super_admin',
26
+        'define_via_gate' => false,
27
+        'intercept_gate' => 'before', // after
28
+    ],
29
+
30
+    'panel_user' => [
31
+        'enabled' => true,
32
+        'name' => 'panel_user',
33
+    ],
34
+
35
+    'permission_prefixes' => [
36
+        'resource' => [
37
+            'view',
38
+            'view_any',
39
+            'create',
40
+            'update',
41
+            'restore',
42
+            'restore_any',
43
+            'replicate',
44
+            'reorder',
45
+            'delete',
46
+            'delete_any',
47
+            'force_delete',
48
+            'force_delete_any',
49
+        ],
50
+
51
+        'page' => 'page',
52
+        'widget' => 'widget',
53
+    ],
54
+
55
+    'entities' => [
56
+        'pages' => true,
57
+        'widgets' => true,
58
+        'resources' => true,
59
+        'custom_permissions' => false,
60
+    ],
61
+
62
+    'generator' => [
63
+        'option' => 'policies_and_permissions',
64
+        'policy_directory' => 'Policies',
65
+        'policy_namespace' => 'Policies',
66
+    ],
67
+
68
+    'exclude' => [
69
+        'enabled' => true,
70
+
71
+        'pages' => [
72
+            'Dashboard',
73
+        ],
74
+
75
+        'widgets' => [
76
+            'AccountWidget', 'FilamentInfoWidget',
77
+        ],
78
+
79
+        'resources' => [],
80
+    ],
81
+
82
+    'discovery' => [
83
+        'discover_all_resources' => false,
84
+        'discover_all_widgets' => false,
85
+        'discover_all_pages' => false,
86
+    ],
87
+
88
+    'register_role_policy' => [
89
+        'enabled' => true,
90
+    ],
91
+
92
+];

+ 101
- 0
config/filament.php 查看文件

@@ -0,0 +1,101 @@
1
+<?php
2
+
3
+return [
4
+
5
+    /*
6
+    |--------------------------------------------------------------------------
7
+    | Broadcasting
8
+    |--------------------------------------------------------------------------
9
+    |
10
+    | By uncommenting the Laravel Echo configuration, you may connect Filament
11
+    | to any Pusher-compatible websockets server.
12
+    |
13
+    | This will allow your users to receive real-time notifications.
14
+    |
15
+    */
16
+
17
+    'broadcasting' => [
18
+
19
+        // 'echo' => [
20
+        //     'broadcaster' => 'pusher',
21
+        //     'key' => env('VITE_PUSHER_APP_KEY'),
22
+        //     'cluster' => env('VITE_PUSHER_APP_CLUSTER'),
23
+        //     'wsHost' => env('VITE_PUSHER_HOST'),
24
+        //     'wsPort' => env('VITE_PUSHER_PORT'),
25
+        //     'wssPort' => env('VITE_PUSHER_PORT'),
26
+        //     'authEndpoint' => '/broadcasting/auth',
27
+        //     'disableStats' => true,
28
+        //     'encrypted' => true,
29
+        //     'forceTLS' => true,
30
+        // ],
31
+
32
+    ],
33
+
34
+    /*
35
+    |--------------------------------------------------------------------------
36
+    | Default Filesystem Disk
37
+    |--------------------------------------------------------------------------
38
+    |
39
+    | This is the storage disk Filament will use to store files. You may use
40
+    | any of the disks defined in the `config/filesystems.php`.
41
+    |
42
+    */
43
+
44
+    'default_filesystem_disk' => env('FILAMENT_FILESYSTEM_DISK', 'public'),
45
+
46
+    /*
47
+    |--------------------------------------------------------------------------
48
+    | Assets Path
49
+    |--------------------------------------------------------------------------
50
+    |
51
+    | This is the directory where Filament's assets will be published to. It
52
+    | is relative to the `public` directory of your Laravel application.
53
+    |
54
+    | After changing the path, you should run `php artisan filament:assets`.
55
+    |
56
+    */
57
+
58
+    'assets_path' => null,
59
+
60
+    /*
61
+    |--------------------------------------------------------------------------
62
+    | Cache Path
63
+    |--------------------------------------------------------------------------
64
+    |
65
+    | This is the directory that Filament will use to store cache files that
66
+    | are used to optimize the registration of components.
67
+    |
68
+    | After changing the path, you should run `php artisan filament:cache-components`.
69
+    |
70
+    */
71
+
72
+    'cache_path' => base_path('bootstrap/cache/filament'),
73
+
74
+    /*
75
+    |--------------------------------------------------------------------------
76
+    | Livewire Loading Delay
77
+    |--------------------------------------------------------------------------
78
+    |
79
+    | This sets the delay before loading indicators appear.
80
+    |
81
+    | Setting this to 'none' makes indicators appear immediately, which can be
82
+    | desirable for high-latency connections. Setting it to 'default' applies
83
+    | Livewire's standard 200ms delay.
84
+    |
85
+    */
86
+
87
+    'livewire_loading_delay' => 'default',
88
+
89
+    /*
90
+    |--------------------------------------------------------------------------
91
+    | System Route Prefix
92
+    |--------------------------------------------------------------------------
93
+    |
94
+    | This is the prefix used for the system routes that Filament registers,
95
+    | such as the routes for downloading exports and failed import rows.
96
+    |
97
+    */
98
+
99
+    'system_route_prefix' => 'filament',
100
+
101
+];

+ 1
- 1
config/filesystems.php 查看文件

@@ -13,7 +13,7 @@ return [
13 13
     |
14 14
     */
15 15
 
16
-    'default' => env('FILESYSTEM_DISK', 'local'),
16
+    'default' => env('FILESYSTEM_DISK', 'public'),
17 17
 
18 18
     /*
19 19
     |--------------------------------------------------------------------------

+ 160
- 0
config/livewire.php 查看文件

@@ -0,0 +1,160 @@
1
+<?php
2
+
3
+return [
4
+
5
+    /*
6
+    |---------------------------------------------------------------------------
7
+    | Class Namespace
8
+    |---------------------------------------------------------------------------
9
+    |
10
+    | This value sets the root class namespace for Livewire component classes in
11
+    | your application. This value will change where component auto-discovery
12
+    | finds components. It's also referenced by the file creation commands.
13
+    |
14
+    */
15
+
16
+    'class_namespace' => 'App\\Livewire',
17
+
18
+    /*
19
+    |---------------------------------------------------------------------------
20
+    | View Path
21
+    |---------------------------------------------------------------------------
22
+    |
23
+    | This value is used to specify where Livewire component Blade templates are
24
+    | stored when running file creation commands like `artisan make:livewire`.
25
+    | It is also used if you choose to omit a component's render() method.
26
+    |
27
+    */
28
+
29
+    'view_path' => resource_path('views/livewire'),
30
+
31
+    /*
32
+    |---------------------------------------------------------------------------
33
+    | Layout
34
+    |---------------------------------------------------------------------------
35
+    | The view that will be used as the layout when rendering a single component
36
+    | as an entire page via `Route::get('/post/create', CreatePost::class);`.
37
+    | In this case, the view returned by CreatePost will render into $slot.
38
+    |
39
+    */
40
+
41
+    'layout' => 'components.layouts.app',
42
+
43
+    /*
44
+    |---------------------------------------------------------------------------
45
+    | Lazy Loading Placeholder
46
+    |---------------------------------------------------------------------------
47
+    | Livewire allows you to lazy load components that would otherwise slow down
48
+    | the initial page load. Every component can have a custom placeholder or
49
+    | you can define the default placeholder view for all components below.
50
+    |
51
+    */
52
+
53
+    'lazy_placeholder' => null,
54
+
55
+    /*
56
+    |---------------------------------------------------------------------------
57
+    | Temporary File Uploads
58
+    |---------------------------------------------------------------------------
59
+    |
60
+    | Livewire handles file uploads by storing uploads in a temporary directory
61
+    | before the file is stored permanently. All file uploads are directed to
62
+    | a global endpoint for temporary storage. You may configure this below:
63
+    |
64
+    */
65
+
66
+    'temporary_file_upload' => [
67
+        'disk' => null,        // Example: 'local', 's3'              | Default: 'default'
68
+        'rules' => ["max:122880"],       // Example: ['file', 'mimes:png,jpg']  | Default: ['required', 'file', 'max:12288'] (12MB)
69
+        'directory' => null,   // Example: 'tmp'                      | Default: 'livewire-tmp'
70
+        'middleware' => null,  // Example: 'throttle:5,1'             | Default: 'throttle:60,1'
71
+        'preview_mimes' => [   // Supported file types for temporary pre-signed file URLs...
72
+            'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
73
+            'mov', 'avi', 'wmv', 'mp3', 'm4a',
74
+            'jpg', 'jpeg', 'mpga', 'webp', 'wma',
75
+        ],
76
+        'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
77
+        'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs...
78
+    ],
79
+
80
+    /*
81
+    |---------------------------------------------------------------------------
82
+    | Render On Redirect
83
+    |---------------------------------------------------------------------------
84
+    |
85
+    | This value determines if Livewire will run a component's `render()` method
86
+    | after a redirect has been triggered using something like `redirect(...)`
87
+    | Setting this to true will render the view once more before redirecting
88
+    |
89
+    */
90
+
91
+    'render_on_redirect' => false,
92
+
93
+    /*
94
+    |---------------------------------------------------------------------------
95
+    | Eloquent Model Binding
96
+    |---------------------------------------------------------------------------
97
+    |
98
+    | Previous versions of Livewire supported binding directly to eloquent model
99
+    | properties using wire:model by default. However, this behavior has been
100
+    | deemed too "magical" and has therefore been put under a feature flag.
101
+    |
102
+    */
103
+
104
+    'legacy_model_binding' => false,
105
+
106
+    /*
107
+    |---------------------------------------------------------------------------
108
+    | Auto-inject Frontend Assets
109
+    |---------------------------------------------------------------------------
110
+    |
111
+    | By default, Livewire automatically injects its JavaScript and CSS into the
112
+    | <head> and <body> of pages containing Livewire components. By disabling
113
+    | this behavior, you need to use @livewireStyles and @livewireScripts.
114
+    |
115
+    */
116
+
117
+    'inject_assets' => true,
118
+
119
+    /*
120
+    |---------------------------------------------------------------------------
121
+    | Navigate (SPA mode)
122
+    |---------------------------------------------------------------------------
123
+    |
124
+    | By adding `wire:navigate` to links in your Livewire application, Livewire
125
+    | will prevent the default link handling and instead request those pages
126
+    | via AJAX, creating an SPA-like effect. Configure this behavior here.
127
+    |
128
+    */
129
+
130
+    'navigate' => [
131
+        'show_progress_bar' => true,
132
+        'progress_bar_color' => '#2299dd',
133
+    ],
134
+
135
+    /*
136
+    |---------------------------------------------------------------------------
137
+    | HTML Morph Markers
138
+    |---------------------------------------------------------------------------
139
+    |
140
+    | Livewire intelligently "morphs" existing HTML into the newly rendered HTML
141
+    | after each update. To make this process more reliable, Livewire injects
142
+    | "markers" into the rendered Blade surrounding @if, @class & @foreach.
143
+    |
144
+    */
145
+
146
+    'inject_morph_markers' => true,
147
+
148
+    /*
149
+    |---------------------------------------------------------------------------
150
+    | Pagination Theme
151
+    |---------------------------------------------------------------------------
152
+    |
153
+    | When enabling Livewire's pagination feature by using the `WithPagination`
154
+    | trait, Livewire will use Tailwind templates to render pagination views
155
+    | on the page. If you want Bootstrap CSS, you can specify: "bootstrap"
156
+    |
157
+    */
158
+
159
+    'pagination_theme' => 'tailwind',
160
+];

+ 33
- 0
database/migrations/2025_09_04_072958_create_banners_table.php 查看文件

@@ -0,0 +1,33 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('banners', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->json("title")->nullable()->comment("大字標題");
17
+            $table->json("content")->nullable()->comment("小標字體");
18
+            $table->string("img_url")->comment("image url");
19
+            $table->json("img_alt")->comment("alt");
20
+            $table->integer("order")->default(0);
21
+            $table->boolean("visible")->default(1);
22
+            $table->timestamps();
23
+        });
24
+    }
25
+
26
+    /**
27
+     * Reverse the migrations.
28
+     */
29
+    public function down(): void
30
+    {
31
+        Schema::dropIfExists('banners');
32
+    }
33
+};

+ 35
- 0
database/migrations/2025_09_04_073017_create_histories_table.php 查看文件

@@ -0,0 +1,35 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('histories', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->string('selected_year')->comment("年份");
17
+            $table->string('selected_month')->comment("月份");
18
+            $table->dateTime('operate_date')->nullable()->comment("日期 暫時用不到 預留可能以後需要");
19
+            $table->json('title')->comment("標題");
20
+            $table->string('img_url')->nullable()->comment("圖片");
21
+            $table->json('img_alt')->nullable()->comment("圖片註釋");
22
+            $table->boolean('visible')->default(1)->comment("顯示/隱藏");
23
+            $table->timestamps();
24
+            $table->softDeletes();
25
+        });
26
+    }
27
+
28
+    /**
29
+     * Reverse the migrations.
30
+     */
31
+    public function down(): void
32
+    {
33
+        Schema::dropIfExists('histories');
34
+    }
35
+};

+ 34
- 0
database/migrations/2025_09_04_073235_create_profile_parts_table.php 查看文件

@@ -0,0 +1,34 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('profile_parts', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->json("title");
17
+            $table->json("content");
18
+            $table->string("img_url");
19
+            $table->json("img_alt");
20
+            $table->integer("order")->default(0);
21
+            $table->boolean("visible")->default(true);
22
+            $table->timestamps();
23
+            $table->softDeletes();
24
+        });
25
+    }
26
+
27
+    /**
28
+     * Reverse the migrations.
29
+     */
30
+    public function down(): void
31
+    {
32
+        Schema::dropIfExists('profile_parts');
33
+    }
34
+};

+ 31
- 0
database/migrations/2025_09_04_073459_create_news_categories_table.php 查看文件

@@ -0,0 +1,31 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('news_categories', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->json("name");
17
+            $table->integer("order")->default(0);
18
+            $table->boolean("visible")->default(0);
19
+            $table->timestamps();
20
+            $table->softDeletes();
21
+        });
22
+    }
23
+
24
+    /**
25
+     * Reverse the migrations.
26
+     */
27
+    public function down(): void
28
+    {
29
+        Schema::dropIfExists('news_categories');
30
+    }
31
+};

+ 45
- 0
database/migrations/2025_09_04_073524_create_news_table.php 查看文件

@@ -0,0 +1,45 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::disableForeignKeyConstraints();
15
+
16
+        Schema::create('news', function (Blueprint $table) {
17
+            $table->id();
18
+            $table->foreignId('news_category_id')->references('id')->on('news_categories')->comment('文章類別');
19
+            $table->string('news_img')->nullable()->comment('列表圖');
20
+            $table->json('title')->comment("標題");
21
+            $table->json('description')->nullable()->comment("短文");
22
+            $table->json('written_by')->comment("編輯人");
23
+            $table->dateTime('post_date')->comment("文章發布日");
24
+            $table->string('meta_img')->nullable()->comment('seo image');
25
+            $table->json("meta_title")->nullable()->comment("seo title");
26
+            $table->json("meta_keyword")->nullable()->comment("seo keyword");
27
+            $table->json("meta_description")->nullable()->comment("seo description");
28
+            $table->boolean('on_top')->default(0)->comment("置頂");
29
+            $table->boolean('visible')->default(1)->comment("顯示/隱藏");
30
+            $table->unsignedInteger('order')->default(0)->comment("排序");
31
+            $table->timestamps();
32
+            $table->softDeletes();
33
+        });
34
+
35
+        Schema::enableForeignKeyConstraints();
36
+    }
37
+
38
+    /**
39
+     * Reverse the migrations.
40
+     */
41
+    public function down(): void
42
+    {
43
+        Schema::dropIfExists('news');
44
+    }
45
+};

+ 33
- 0
database/migrations/2025_09_17_033657_create_news_paragraphs_table.php 查看文件

@@ -0,0 +1,33 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::disableForeignKeyConstraints();
15
+
16
+        Schema::create('news_paragraphs', function (Blueprint $table) {
17
+            $table->id();
18
+            $table->foreignId('news_id')->references('id')->on('news')->comment("關聯文章");
19
+            $table->unsignedTinyInteger('paragraph_type')->comment('段落類型 1.images 2.text');
20
+            $table->json('text_content')->nullable()->comment("文字段落");
21
+            $table->unsignedInteger('order')->default(0)->comment("排序");
22
+        });
23
+        Schema::enableForeignKeyConstraints();
24
+    }
25
+
26
+    /**
27
+     * Reverse the migrations.
28
+     */
29
+    public function down(): void
30
+    {
31
+        Schema::dropIfExists('news_paragraphs');
32
+    }
33
+};

+ 30
- 0
database/migrations/2025_09_17_033730_create_tags_table.php 查看文件

@@ -0,0 +1,30 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('tags', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->json("name")->comment("標籤名稱");
17
+            $table->integer("order")->default(0);
18
+            $table->boolean("visible")->default(1);
19
+            $table->timestamps();
20
+        });
21
+    }
22
+
23
+    /**
24
+     * Reverse the migrations.
25
+     */
26
+    public function down(): void
27
+    {
28
+        Schema::dropIfExists('tags');
29
+    }
30
+};

+ 32
- 0
database/migrations/2025_09_17_033900_create_badges_table.php 查看文件

@@ -0,0 +1,32 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('badges', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->json("title")->nullable()->comment("標題");
17
+            $table->string("img_url")->comment("image url");
18
+            $table->json("img_alt")->comment("alt");
19
+            $table->integer("order")->default(0);
20
+            $table->boolean("visible")->default(1);
21
+            $table->timestamps();
22
+        });
23
+    }
24
+
25
+    /**
26
+     * Reverse the migrations.
27
+     */
28
+    public function down(): void
29
+    {
30
+        Schema::dropIfExists('badges');
31
+    }
32
+};

+ 34
- 0
database/migrations/2025_09_18_033227_create_news_paragraph_photos_table.php 查看文件

@@ -0,0 +1,34 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::disableForeignKeyConstraints();
15
+
16
+        Schema::create('news_paragraph_photos', function (Blueprint $table) {
17
+            $table->id();
18
+            $table->foreignId('news_paragraph_id')->references('id')->on('news_paragraphs')->comment("關聯文章段落");
19
+            $table->string('img_url')->nullable()->comment("圖片網址");
20
+            $table->json('img_alt')->nullable()->comment("圖片註釋");
21
+            $table->unsignedInteger('order')->default(0)->comment("排序");
22
+        });
23
+
24
+        Schema::enableForeignKeyConstraints();
25
+    }
26
+
27
+    /**
28
+     * Reverse the migrations.
29
+     */
30
+    public function down(): void
31
+    {
32
+        Schema::dropIfExists('news_paragraph_photos');
33
+    }
34
+};

+ 38
- 0
database/migrations/2025_09_18_091406_create_projects_table.php 查看文件

@@ -0,0 +1,38 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::disableForeignKeyConstraints();
15
+        Schema::create('projects', function (Blueprint $table) {
16
+            $table->id();
17
+            $table->foreignId('region_id')->references('id')->on('regions')->comment('所屬地區');
18
+            $table->json("name")->comment("專案項目名稱");
19
+            $table->json("address")->comment("基本資料: 地址");
20
+            $table->json("floor_plan")->comment("樓層規劃");
21
+            $table->json("building_structure")->comment("建築結構");
22
+            $table->json("design_unit")->comment("設計團隊");
23
+            $table->json("contact_info")->comment("聯絡資訊");
24
+            $table->timestamps();
25
+            $table->softDeletes();
26
+        });
27
+
28
+        Schema::enableForeignKeyConstraints();
29
+    }
30
+
31
+    /**
32
+     * Reverse the migrations.
33
+     */
34
+    public function down(): void
35
+    {
36
+        Schema::dropIfExists('projects');
37
+    }
38
+};

+ 31
- 0
database/migrations/2025_09_18_092245_create_regions_table.php 查看文件

@@ -0,0 +1,31 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('regions', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->json("name")->comment("名稱");
17
+            $table->integer("order")->default(0);
18
+            $table->boolean("visible")->default(1);
19
+            $table->timestamps();
20
+            $table->softDeletes();
21
+        });
22
+    }
23
+
24
+    /**
25
+     * Reverse the migrations.
26
+     */
27
+    public function down(): void
28
+    {
29
+        Schema::dropIfExists('regions');
30
+    }
31
+};

+ 32
- 0
database/migrations/2025_09_18_092318_create_project_histories_table.php 查看文件

@@ -0,0 +1,32 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('project_histories', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('project_id')->references('id')->on('projects')->comment('所屬專案');
17
+            $table->date('operate_date')->nullable()->comment("紀錄日期");
18
+            $table->json('title')->comment("標題");
19
+            $table->boolean('visible')->default(1)->comment("顯示/隱藏");
20
+            $table->timestamps();
21
+            $table->softDeletes();
22
+        });
23
+    }
24
+
25
+    /**
26
+     * Reverse the migrations.
27
+     */
28
+    public function down(): void
29
+    {
30
+        Schema::dropIfExists('project_histories');
31
+    }
32
+};

+ 37
- 0
database/migrations/2025_09_18_092430_create_project_summaries_table.php 查看文件

@@ -0,0 +1,37 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::disableForeignKeyConstraints();
15
+
16
+        Schema::create('project_summaries', function (Blueprint $table) {
17
+            $table->id();
18
+            $table->foreignId('project_id')->references('id')->on('projects')->comment('所屬專案');
19
+            $table->json("title");
20
+            $table->json("content");
21
+            $table->integer("order")->default(0);
22
+            $table->boolean("visible")->default(true);
23
+            $table->timestamps();
24
+            $table->softDeletes();
25
+        });
26
+
27
+        Schema::enableForeignKeyConstraints();
28
+    }
29
+
30
+    /**
31
+     * Reverse the migrations.
32
+     */
33
+    public function down(): void
34
+    {
35
+        Schema::dropIfExists('project_summaries');
36
+    }
37
+};

+ 31
- 0
database/migrations/2025_09_18_093917_create_taggables_table.php 查看文件

@@ -0,0 +1,31 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('taggables', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('tag_id')->constrained()->cascadeOnDelete();
17
+            $table->morphs('taggable'); // 創建 taggable_id 和 taggable_type
18
+            $table->timestamps();
19
+
20
+            $table->unique(['tag_id', 'taggable_id', 'taggable_type']);
21
+        });
22
+    }
23
+
24
+    /**
25
+     * Reverse the migrations.
26
+     */
27
+    public function down(): void
28
+    {
29
+        Schema::dropIfExists('taggables');
30
+    }
31
+};

+ 31
- 0
database/migrations/2025_09_18_093938_create_badgeables_table.php 查看文件

@@ -0,0 +1,31 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('badgeables', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('badge_id')->constrained()->cascadeOnDelete();
17
+            $table->morphs('badgeable'); // 創建 taggable_id 和 taggable_type
18
+            $table->timestamps();
19
+
20
+            $table->unique(['badge_id', 'badgeable_id', 'badgeable_type']);
21
+        });
22
+    }
23
+
24
+    /**
25
+     * Reverse the migrations.
26
+     */
27
+    public function down(): void
28
+    {
29
+        Schema::dropIfExists('badgeables');
30
+    }
31
+};

+ 35
- 0
database/migrations/2025_09_19_111819_create_project_space_infos_table.php 查看文件

@@ -0,0 +1,35 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::disableForeignKeyConstraints();
15
+        Schema::create('project_space_infos', function (Blueprint $table) {
16
+            $table->id();
17
+            $table->foreignId('project_id')->references('id')->on('projects')->comment('所屬專案');
18
+            $table->json("title");
19
+            $table->json("content");
20
+            $table->integer("order")->default(0);
21
+            $table->boolean("visible")->default(true);
22
+            $table->timestamps();
23
+            $table->softDeletes();
24
+        });
25
+        Schema::enableForeignKeyConstraints();
26
+    }
27
+
28
+    /**
29
+     * Reverse the migrations.
30
+     */
31
+    public function down(): void
32
+    {
33
+        Schema::dropIfExists('project_space_infos');
34
+    }
35
+};

+ 12
- 0
lang/vendor/filament-panels/ar/global-search.php 查看文件

@@ -0,0 +1,12 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'field' => [
6
+        'label' => 'بحث عام',
7
+        'placeholder' => 'بحث',
8
+    ],
9
+
10
+    'no_results_message' => 'لم يتم العثور على نتائج عن البحث.',
11
+
12
+];

+ 63
- 0
lang/vendor/filament-panels/ar/layout.php 查看文件

@@ -0,0 +1,63 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'direction' => 'rtl',
6
+
7
+    'actions' => [
8
+
9
+        'billing' => [
10
+            'label' => 'إدارة الاشتراكات',
11
+        ],
12
+
13
+        'logout' => [
14
+            'label' => 'تسجيل الخروج',
15
+        ],
16
+
17
+        'open_database_notifications' => [
18
+            'label' => 'عرض التنبيهات',
19
+        ],
20
+
21
+        'open_user_menu' => [
22
+            'label' => 'قائمة المستخدم',
23
+        ],
24
+
25
+        'sidebar' => [
26
+
27
+            'collapse' => [
28
+                'label' => 'طيّ القائمة الجانبية',
29
+            ],
30
+
31
+            'expand' => [
32
+                'label' => 'توسيع القائمة الجانبية',
33
+            ],
34
+
35
+        ],
36
+
37
+        'theme_switcher' => [
38
+
39
+            'dark' => [
40
+                'label' => 'تفعيل الوضع الليلي',
41
+            ],
42
+
43
+            'light' => [
44
+                'label' => 'تفعيل الوضع النهاري',
45
+            ],
46
+
47
+            'system' => [
48
+                'label' => 'تفعيل سمة النظام',
49
+            ],
50
+
51
+        ],
52
+
53
+    ],
54
+
55
+    'avatar' => [
56
+        'alt' => 'صورة شخصية لـ :name',
57
+    ],
58
+
59
+    'logo' => [
60
+        'alt' => ':name شعار',
61
+    ],
62
+
63
+];

+ 51
- 0
lang/vendor/filament-panels/ar/pages/auth/edit-profile.php 查看文件

@@ -0,0 +1,51 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'label' => 'الملف الشخصي',
6
+
7
+    'form' => [
8
+
9
+        'email' => [
10
+            'label' => 'البريد الإلكتروني',
11
+        ],
12
+
13
+        'name' => [
14
+            'label' => 'الاسم',
15
+        ],
16
+
17
+        'password' => [
18
+            'label' => 'كلمة المرور الجديدة',
19
+        ],
20
+
21
+        'password_confirmation' => [
22
+            'label' => 'تأكيد كلمة المرور الجديدة',
23
+        ],
24
+
25
+        'actions' => [
26
+
27
+            'save' => [
28
+                'label' => 'حفظ التغييرات',
29
+            ],
30
+
31
+        ],
32
+
33
+    ],
34
+
35
+    'notifications' => [
36
+
37
+        'saved' => [
38
+            'title' => 'تم الحفظ',
39
+        ],
40
+
41
+    ],
42
+
43
+    'actions' => [
44
+
45
+        'cancel' => [
46
+            'label' => 'إلغاء',
47
+        ],
48
+
49
+    ],
50
+
51
+];

+ 35
- 0
lang/vendor/filament-panels/ar/pages/auth/email-verification/email-verification-prompt.php 查看文件

@@ -0,0 +1,35 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'تحقق من عنوان بريدك الإلكتروني',
6
+
7
+    'heading' => 'تحقق من عنوان بريدك الإلكتروني',
8
+
9
+    'actions' => [
10
+
11
+        'resend_notification' => [
12
+            'label' => 'أعد الإرسال',
13
+        ],
14
+
15
+    ],
16
+
17
+    'messages' => [
18
+        'notification_not_received' => 'لم تستلم البريد الذي قمنا بإرساله؟',
19
+        'notification_sent' => 'لقد أرسلنا بريدًا إلكترونيًا إلى :email يحتوي على تعليمات حول كيفية التحقق من عنوان بريدك الإلكتروني.',
20
+    ],
21
+
22
+    'notifications' => [
23
+
24
+        'notification_resent' => [
25
+            'title' => 'لقد قمنا بإعادة إرسال البريد الإلكتروني.',
26
+        ],
27
+
28
+        'notification_resend_throttled' => [
29
+            'title' => 'لقد قمت بمحاولات إعادة إرسال كثيرة جداً',
30
+            'body' => 'يرجى المحاولة مرة أخرى بعد :seconds ثواني.',
31
+        ],
32
+
33
+    ],
34
+
35
+];

+ 61
- 0
lang/vendor/filament-panels/ar/pages/auth/login.php 查看文件

@@ -0,0 +1,61 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'تسجيل الدخول',
6
+
7
+    'heading' => 'الدخول إلى حسابك',
8
+
9
+    'actions' => [
10
+
11
+        'register' => [
12
+            'before' => 'أو',
13
+            'label' => 'إنشاء حساب',
14
+        ],
15
+
16
+        'request_password_reset' => [
17
+            'label' => 'نسيت كلمة المرور؟',
18
+        ],
19
+
20
+    ],
21
+
22
+    'form' => [
23
+
24
+        'email' => [
25
+            'label' => 'البريد الإلكتروني',
26
+        ],
27
+
28
+        'password' => [
29
+            'label' => 'كلمة المرور',
30
+        ],
31
+
32
+        'remember' => [
33
+            'label' => 'تذكرني',
34
+        ],
35
+
36
+        'actions' => [
37
+
38
+            'authenticate' => [
39
+                'label' => 'تسجيل الدخول',
40
+            ],
41
+
42
+        ],
43
+
44
+    ],
45
+
46
+    'messages' => [
47
+
48
+        'failed' => 'بيانات الاعتماد هذه غير متطابقة مع البيانات المسجلة لدينا.',
49
+
50
+    ],
51
+
52
+    'notifications' => [
53
+
54
+        'throttled' => [
55
+            'title' => 'لقد قمت بمحاولات تسجيل دخول كثيرة جدًا',
56
+            'body' => 'يرجى المحاولة مرة أخرى بعد :seconds ثواني.',
57
+        ],
58
+
59
+    ],
60
+
61
+];

+ 44
- 0
lang/vendor/filament-panels/ar/pages/auth/password-reset/request-password-reset.php 查看文件

@@ -0,0 +1,44 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'استعادة كلمة المرور',
6
+
7
+    'heading' => 'نسيت كلمة المرور؟',
8
+
9
+    'actions' => [
10
+
11
+        'login' => [
12
+            'label' => 'العودة لتسجيل الدخول',
13
+        ],
14
+
15
+    ],
16
+
17
+    'form' => [
18
+
19
+        'email' => [
20
+            'label' => 'البريد الإلكتروني',
21
+        ],
22
+
23
+        'actions' => [
24
+
25
+            'request' => [
26
+                'label' => 'أرسل البريد الإلكتروني',
27
+            ],
28
+
29
+        ],
30
+
31
+    ],
32
+
33
+    'notifications' => [
34
+        'sent' => [
35
+            'body' => 'إذا لم يكن حسابك موجودًا، فلن تتلقى البريد الإلكتروني.',
36
+        ],
37
+        'throttled' => [
38
+            'title' => 'لقد قمت بمحاولات كثيرة جداً',
39
+            'body' => 'يرجى المحاولة مرة أخرى بعد :seconds ثواني.',
40
+        ],
41
+
42
+    ],
43
+
44
+];

+ 43
- 0
lang/vendor/filament-panels/ar/pages/auth/password-reset/reset-password.php 查看文件

@@ -0,0 +1,43 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'إعادة تعيين كلمة المرور',
6
+
7
+    'heading' => 'إعادة تعيين كلمة المرور',
8
+
9
+    'form' => [
10
+
11
+        'email' => [
12
+            'label' => 'البريد الإلكتروني',
13
+        ],
14
+
15
+        'password' => [
16
+            'label' => 'كلمة المرور',
17
+            'validation_attribute' => 'كلمة المرور',
18
+        ],
19
+
20
+        'password_confirmation' => [
21
+            'label' => 'تأكيد كلمة المرور',
22
+        ],
23
+
24
+        'actions' => [
25
+
26
+            'reset' => [
27
+                'label' => 'إعادة تعيين كلمة المرور',
28
+            ],
29
+
30
+        ],
31
+
32
+    ],
33
+
34
+    'notifications' => [
35
+
36
+        'throttled' => [
37
+            'title' => 'لقد قمت بمحاولات كثيرة جداً لإعادة تعيين كلمة المرور',
38
+            'body' => 'يرجى المحاولة مرة أخرى بعد :seconds ثواني.',
39
+        ],
40
+
41
+    ],
42
+
43
+];

+ 56
- 0
lang/vendor/filament-panels/ar/pages/auth/register.php 查看文件

@@ -0,0 +1,56 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'تسجيل',
6
+
7
+    'heading' => 'إنشاء حساب',
8
+
9
+    'actions' => [
10
+
11
+        'login' => [
12
+            'before' => 'أو',
13
+            'label' => 'سجل الدخول لحسابك',
14
+        ],
15
+
16
+    ],
17
+
18
+    'form' => [
19
+
20
+        'email' => [
21
+            'label' => 'البريد الإلكتروني',
22
+        ],
23
+
24
+        'name' => [
25
+            'label' => 'الاسم',
26
+        ],
27
+
28
+        'password' => [
29
+            'label' => 'كلمة المرور',
30
+            'validation_attribute' => 'كلمة المرور',
31
+        ],
32
+
33
+        'password_confirmation' => [
34
+            'label' => 'تأكيد كلمة المرور',
35
+        ],
36
+
37
+        'actions' => [
38
+
39
+            'register' => [
40
+                'label' => 'إنشاء حساب',
41
+            ],
42
+
43
+        ],
44
+
45
+    ],
46
+
47
+    'notifications' => [
48
+
49
+        'throttled' => [
50
+            'title' => 'لقد قمت بمحاولات تسجيل كثيرة جدًا',
51
+            'body' => 'يرجى المحاولة مرة أخرى بعد :seconds ثواني.',
52
+        ],
53
+
54
+    ],
55
+
56
+];

+ 33
- 0
lang/vendor/filament-panels/ar/pages/dashboard.php 查看文件

@@ -0,0 +1,33 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'لوحة التحكم',
6
+
7
+    'actions' => [
8
+
9
+        'filter' => [
10
+
11
+            'label' => 'تصفية',
12
+
13
+            'modal' => [
14
+
15
+                'heading' => 'تصفية',
16
+
17
+                'actions' => [
18
+
19
+                    'apply' => [
20
+
21
+                        'label' => 'تطبيق',
22
+
23
+                    ],
24
+
25
+                ],
26
+
27
+            ],
28
+
29
+        ],
30
+
31
+    ],
32
+
33
+];

+ 25
- 0
lang/vendor/filament-panels/ar/pages/tenancy/edit-tenant-profile.php 查看文件

@@ -0,0 +1,25 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'form' => [
6
+
7
+        'actions' => [
8
+
9
+            'save' => [
10
+                'label' => 'حفظ التغييرات',
11
+            ],
12
+
13
+        ],
14
+
15
+    ],
16
+
17
+    'notifications' => [
18
+
19
+        'saved' => [
20
+            'title' => 'تم الحفظ',
21
+        ],
22
+
23
+    ],
24
+
25
+];

+ 37
- 0
lang/vendor/filament-panels/ar/resources/pages/create-record.php 查看文件

@@ -0,0 +1,37 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'إضافة :label',
6
+
7
+    'breadcrumb' => 'إضافة',
8
+
9
+    'form' => [
10
+
11
+        'actions' => [
12
+
13
+            'cancel' => [
14
+                'label' => 'إلغاء',
15
+            ],
16
+
17
+            'create' => [
18
+                'label' => 'إضافة',
19
+            ],
20
+
21
+            'create_another' => [
22
+                'label' => 'إضافة وبدء إضافة المزيد',
23
+            ],
24
+
25
+        ],
26
+
27
+    ],
28
+
29
+    'notifications' => [
30
+
31
+        'created' => [
32
+            'title' => 'تمت الإضافة',
33
+        ],
34
+
35
+    ],
36
+
37
+];

+ 41
- 0
lang/vendor/filament-panels/ar/resources/pages/edit-record.php 查看文件

@@ -0,0 +1,41 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'تعديل :label',
6
+
7
+    'breadcrumb' => 'تعديل',
8
+
9
+    'form' => [
10
+
11
+        'actions' => [
12
+
13
+            'cancel' => [
14
+                'label' => 'إلغاء',
15
+            ],
16
+
17
+            'save' => [
18
+                'label' => 'حفظ التغييرات',
19
+            ],
20
+
21
+        ],
22
+
23
+    ],
24
+
25
+    'content' => [
26
+
27
+        'tab' => [
28
+            'label' => 'تعديل',
29
+        ],
30
+
31
+    ],
32
+
33
+    'notifications' => [
34
+
35
+        'saved' => [
36
+            'title' => 'تم الحفظ',
37
+        ],
38
+
39
+    ],
40
+
41
+];

+ 7
- 0
lang/vendor/filament-panels/ar/resources/pages/list-records.php 查看文件

@@ -0,0 +1,7 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'breadcrumb' => 'القائمة',
6
+
7
+];

+ 17
- 0
lang/vendor/filament-panels/ar/resources/pages/view-record.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'عرض :label',
6
+
7
+    'breadcrumb' => 'عرض',
8
+
9
+    'content' => [
10
+
11
+        'tab' => [
12
+            'label' => 'عرض',
13
+        ],
14
+
15
+    ],
16
+
17
+];

+ 7
- 0
lang/vendor/filament-panels/ar/unsaved-changes-alert.php 查看文件

@@ -0,0 +1,7 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'body' => 'توجد لديك تغييرات غير محفوظة. هل أنت متأكد من أنك تريد مغادرة هذه الصفحة؟',
6
+
7
+];

+ 15
- 0
lang/vendor/filament-panels/ar/widgets/account-widget.php 查看文件

@@ -0,0 +1,15 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'actions' => [
6
+
7
+        'logout' => [
8
+            'label' => 'تسجيل الخروج',
9
+        ],
10
+
11
+    ],
12
+
13
+    'welcome' => 'مرحباً',
14
+
15
+];

+ 17
- 0
lang/vendor/filament-panels/ar/widgets/filament-info-widget.php 查看文件

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'actions' => [
6
+
7
+        'open_documentation' => [
8
+            'label' => 'الوثائق',
9
+        ],
10
+
11
+        'open_github' => [
12
+            'label' => 'GitHub',
13
+        ],
14
+
15
+    ],
16
+
17
+];

+ 12
- 0
lang/vendor/filament-panels/az/global-search.php 查看文件

@@ -0,0 +1,12 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'field' => [
6
+        'label' => 'Ümumi axtarış',
7
+        'placeholder' => 'Axtar',
8
+    ],
9
+
10
+    'no_results_message' => 'Nəticə tapılmadı.',
11
+
12
+];

+ 63
- 0
lang/vendor/filament-panels/az/layout.php 查看文件

@@ -0,0 +1,63 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'direction' => 'ltr',
6
+
7
+    'actions' => [
8
+
9
+        'billing' => [
10
+            'label' => 'Abunəliyi idarə et',
11
+        ],
12
+
13
+        'logout' => [
14
+            'label' => 'Çıxış',
15
+        ],
16
+
17
+        'open_database_notifications' => [
18
+            'label' => 'Bildirişləri aç',
19
+        ],
20
+
21
+        'open_user_menu' => [
22
+            'label' => 'İstifadəçi menyusu',
23
+        ],
24
+
25
+        'sidebar' => [
26
+
27
+            'collapse' => [
28
+                'label' => 'Yan menyunu daralt',
29
+            ],
30
+
31
+            'expand' => [
32
+                'label' => 'Yan menyunu genişlət',
33
+            ],
34
+
35
+        ],
36
+
37
+        'theme_switcher' => [
38
+
39
+            'dark' => [
40
+                'label' => 'Qara tema',
41
+            ],
42
+
43
+            'light' => [
44
+                'label' => 'Açıq tema',
45
+            ],
46
+
47
+            'system' => [
48
+                'label' => 'Sistem defolt',
49
+            ],
50
+
51
+        ],
52
+
53
+    ],
54
+
55
+    'avatar' => [
56
+        'alt' => 'avatarı :name',
57
+    ],
58
+
59
+    'logo' => [
60
+        'alt' => ':name loqo',
61
+    ],
62
+
63
+];

+ 51
- 0
lang/vendor/filament-panels/az/pages/auth/edit-profile.php 查看文件

@@ -0,0 +1,51 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'label' => 'Profil',
6
+
7
+    'form' => [
8
+
9
+        'email' => [
10
+            'label' => 'E-poçt ünvanı',
11
+        ],
12
+
13
+        'name' => [
14
+            'label' => 'Ad',
15
+        ],
16
+
17
+        'password' => [
18
+            'label' => 'Yeni şifrə',
19
+        ],
20
+
21
+        'password_confirmation' => [
22
+            'label' => 'Yeni şifrəni təsdiqlə',
23
+        ],
24
+
25
+        'actions' => [
26
+
27
+            'save' => [
28
+                'label' => 'Dəyişiklikləri Yadda Saxla',
29
+            ],
30
+
31
+        ],
32
+
33
+    ],
34
+
35
+    'notifications' => [
36
+
37
+        'saved' => [
38
+            'title' => 'Yadda saxlanıldı',
39
+        ],
40
+
41
+    ],
42
+
43
+    'actions' => [
44
+
45
+        'cancel' => [
46
+            'label' => 'İmtina',
47
+        ],
48
+
49
+    ],
50
+
51
+];

+ 35
- 0
lang/vendor/filament-panels/az/pages/auth/email-verification/email-verification-prompt.php 查看文件

@@ -0,0 +1,35 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'E-poçt ünvanınızı təsdiqləyin',
6
+
7
+    'heading' => 'E-poçt ünvanınızı təsdiqləyin',
8
+
9
+    'actions' => [
10
+
11
+        'resend_notification' => [
12
+            'label' => 'Yenidən Göndər',
13
+        ],
14
+
15
+    ],
16
+
17
+    'messages' => [
18
+        'notification_not_received' => 'Göndərdiyimiz e-poçt gəlmədi?',
19
+        'notification_sent' => ':email ünvanına, daxilində e-poçt ünvanınızı necə təsdiqləyəcəyiniz barədə təlimatlar olan bir e-poçt göndərdik.',
20
+    ],
21
+
22
+    'notifications' => [
23
+
24
+        'notification_resent' => [
25
+            'title' => 'E-poçt yenidən göndərildi.',
26
+        ],
27
+
28
+        'notification_resend_throttled' => [
29
+            'title' => 'Bir çox yenidən göndərmə cəhdi',
30
+            'body' => 'Zəhmət olmazsa :seconds saniyə sonra təkrar yoxlayın.',
31
+        ],
32
+
33
+    ],
34
+
35
+];

+ 61
- 0
lang/vendor/filament-panels/az/pages/auth/login.php 查看文件

@@ -0,0 +1,61 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'Giriş Et',
6
+
7
+    'heading' => 'Daxil Ol',
8
+
9
+    'actions' => [
10
+
11
+        'register' => [
12
+            'before' => 'və ya',
13
+            'label' => 'hesab yaradın',
14
+        ],
15
+
16
+        'request_password_reset' => [
17
+            'label' => 'Şifrənizi unutmusunuz?',
18
+        ],
19
+
20
+    ],
21
+
22
+    'form' => [
23
+
24
+        'email' => [
25
+            'label' => 'E-poçt ünvanı',
26
+        ],
27
+
28
+        'password' => [
29
+            'label' => 'Şifrə',
30
+        ],
31
+
32
+        'remember' => [
33
+            'label' => 'Məni Xatırla',
34
+        ],
35
+
36
+        'actions' => [
37
+
38
+            'authenticate' => [
39
+                'label' => 'Giriş Et',
40
+            ],
41
+
42
+        ],
43
+
44
+    ],
45
+
46
+    'messages' => [
47
+
48
+        'failed' => 'Daxil etdiyiniz məlumatlara uyğun hesab tapılmadı.',
49
+
50
+    ],
51
+
52
+    'notifications' => [
53
+
54
+        'throttled' => [
55
+            'title' => 'Bir çox giriş cəhdi',
56
+            'body' => 'Zəhmət olmazsa :seconds saniyə sonra təkrar yoxlayın.',
57
+        ],
58
+
59
+    ],
60
+
61
+];

+ 42
- 0
lang/vendor/filament-panels/az/pages/auth/password-reset/request-password-reset.php 查看文件

@@ -0,0 +1,42 @@
1
+<?php
2
+
3
+return [
4
+
5
+    'title' => 'Şifrənizi Sıfırlayın',
6
+
7
+    'heading' => 'Şifrənizi unutmusunuz?',
8
+
9
+    'actions' => [
10
+
11
+        'login' => [
12
+            'label' => 'girişə geri dön',
13
+        ],
14
+
15
+    ],
16
+
17
+    'form' => [
18
+
19
+        'email' => [
20
+            'label' => 'E-poçt ünvanı',
21
+        ],
22
+
23
+        'actions' => [
24
+
25
+            'request' => [
26
+                'label' => 'E-poçt göndər',
27
+            ],
28
+
29
+        ],
30
+
31
+    ],
32
+
33
+    'notifications' => [
34
+
35
+        'throttled' => [
36
+            'title' => 'Bir çox istəmə cəhdi',
37
+            'body' => 'Zəhmət olmazsa :seconds saniyə sonra təkrar yoxlayın.',
38
+        ],
39
+
40
+    ],
41
+
42
+];

+ 0
- 0
lang/vendor/filament-panels/az/pages/auth/password-reset/reset-password.php 查看文件


部分文件因为文件数量过多而无法显示