diff --git a/.DS_Store b/.DS_Store index e700711..eaafb26 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Modules/.DS_Store b/Modules/.DS_Store new file mode 100644 index 0000000..decb605 Binary files /dev/null and b/Modules/.DS_Store differ diff --git a/Modules/CircleApps/App/Services/CircleAppsMenuServices.php b/Modules/CircleApps/App/Services/CircleAppsMenuServices.php index 7892f4c..c196c76 100644 --- a/Modules/CircleApps/App/Services/CircleAppsMenuServices.php +++ b/Modules/CircleApps/App/Services/CircleAppsMenuServices.php @@ -4,7 +4,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; -use Modules\CircleApps\App\Facades\CircleApps; +use Modules\CircleApps\App\Facades\CircleXo; use Spatie\Permission\Models\Role; use TomatoPHP\TomatoAdmin\Facade\TomatoMenu as TomatoMenuFacade; use TomatoPHP\TomatoAdmin\Services\Contracts\Menu; diff --git a/Modules/CircleApps/App/Services/CircleAppsServices.php b/Modules/CircleApps/App/Services/CircleAppsServices.php index 9d30db3..355c5ab 100644 --- a/Modules/CircleApps/App/Services/CircleAppsServices.php +++ b/Modules/CircleApps/App/Services/CircleAppsServices.php @@ -4,8 +4,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; -use Modules\CircleApps\App\Facades\CircleApps; use Modules\CircleApps\App\Facades\CircleAppsMenu; +use Modules\CircleApps\App\Facades\CircleXo; +use Modules\CircleApps\App\Facades\CircleXoSlots; use Spatie\Permission\Models\Role; use TomatoPHP\TomatoAdmin\Facade\TomatoMenu as TomatoMenuFacade; use TomatoPHP\TomatoAdmin\Services\Contracts\Menu; diff --git a/Modules/CircleApps/resources/views/show.blade.php b/Modules/CircleApps/resources/views/show.blade.php index 33a1df0..851b0fd 100644 --- a/Modules/CircleApps/resources/views/show.blade.php +++ b/Modules/CircleApps/resources/views/show.blade.php @@ -68,8 +68,8 @@ -
-
+
+
@@ -78,7 +78,7 @@ @endif
-
+
@if($app->homepage)

{{__('Website')}}

diff --git a/Modules/CircleContacts/App/Providers/CircleContactsServiceProvider.php b/Modules/CircleContacts/App/Providers/CircleContactsServiceProvider.php index 7e96ea6..4a05f7c 100644 --- a/Modules/CircleContacts/App/Providers/CircleContactsServiceProvider.php +++ b/Modules/CircleContacts/App/Providers/CircleContactsServiceProvider.php @@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; use Modules\CircleApps\App\Facades\CircleAppsMenu; +use Modules\CircleApps\App\Facades\CircleXoSlots; use Modules\CircleContacts\App\Console\CircleContactsInstall; use Modules\CircleContacts\App\Console\CircleInovicesInstall; use TomatoPHP\TomatoAdmin\Services\Contracts\Menu; diff --git a/Modules/CircleDocs/.github/FUNDING.yml b/Modules/CircleDocs/.github/FUNDING.yml new file mode 100644 index 0000000..892ba05 --- /dev/null +++ b/Modules/CircleDocs/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [3x1io] diff --git a/Modules/CircleDocs/App/Console/.gitkeep b/Modules/CircleDocs/App/Console/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Console/CircleDocsInstall.php b/Modules/CircleDocs/App/Console/CircleDocsInstall.php new file mode 100644 index 0000000..812b8e8 --- /dev/null +++ b/Modules/CircleDocs/App/Console/CircleDocsInstall.php @@ -0,0 +1,63 @@ +info('Install App'); + $app = App::where('key', 'circle-docs')->first(); + if(!$app){ + $app = new App(); + $app->key = 'circle-docs'; + $app->name = 'Circle Docs'; + $app->description = 'Create and share, search in your docs using markdown editor and GitHub integration'; + $app->is_active = true; + $app->is_free = true; + $app->status = "active"; + $app->homepage = "https://www.github.com/tomatophp/circle-docs"; + $app->github = "https://www.github.com/tomatophp/circle-docs"; + $app->docs = "https://www.github.com/tomatophp/circle-docs"; + $app->privacy = "https://www.github.com/tomatophp/circle-docs"; + $app->faq = "https://www.github.com/tomatophp/circle-docs"; + $app->email = "info@3x1.io"; + $app->save(); + } + $this->callSilent('optimize:clear'); + $this->artisanCommand(["migrate"]); + $this->artisanCommand(["optimize:clear"]); + $this->info('Circle Contacts App installed successfully.'); + } +} diff --git a/Modules/CircleDocs/App/Forms/.gitkeep b/Modules/CircleDocs/App/Forms/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Http/Controllers/.gitkeep b/Modules/CircleDocs/App/Http/Controllers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Http/Controllers/CircleDocsController.php b/Modules/CircleDocs/App/Http/Controllers/CircleDocsController.php new file mode 100644 index 0000000..581ebd0 --- /dev/null +++ b/Modules/CircleDocs/App/Http/Controllers/CircleDocsController.php @@ -0,0 +1,81 @@ +where('is_public', true); + if($request->has('search') && $request->input('search') != ''){ + $query->where('name', 'like', '%'.$request->input('search').'%')->orWhere('package', 'like', '%'.$request->input('search').'%'); + } + $query->where('is_public', true); + $query = $query->paginate(12); + + return view('circle-docs::index', [ + 'docs' => $query + ]); + } + + public function profile($username) + { + $account = Account::where('username', $username)->firstOrFail(); + if($account){ + $query = CircleXoDoc::query(); + $query->where('account_id', $account->id); + $query->where('is_public', true); + $query = $query->paginate(12); + + return view('circle-docs::profile', [ + 'docs' => $query, + 'account' => $account + ]); + } + } + + /** + * Show the specified resource. + */ + public function show($username, $slug) + { + $account = Account::where('username', $username)->firstOrFail(); + if($account){ + $doc = CircleXoDoc::where('package', $slug)->where('account_id', $account->id)->firstOrFail(); + return view('circle-docs::show', [ + 'doc' => $doc, + 'account' => $account + ]); + } + } + + /** + * Show the specified resource. + */ + public function page($username, $slug, $page) + { + $account = Account::where('username', $username)->firstOrFail(); + if($account){ + $doc = CircleXoDoc::where('package', $slug)->where('account_id', $account->id)->firstOrFail(); + if($doc){ + $page = $doc->pages()->where('slug', $page)->firstOrFail(); + return view('circle-docs::show', [ + 'doc' => $doc, + 'currentPage' => $page, + 'account' => $account + ]); + } + } + } +} diff --git a/Modules/CircleDocs/App/Http/Controllers/CircleXoDocController.php b/Modules/CircleDocs/App/Http/Controllers/CircleXoDocController.php new file mode 100644 index 0000000..e36669f --- /dev/null +++ b/Modules/CircleDocs/App/Http/Controllers/CircleXoDocController.php @@ -0,0 +1,207 @@ +model = \Modules\CircleDocs\App\Models\CircleXoDoc::class; + } + + public function like(Request $request) + { + $request->validate([ + "type"=> "required|in:page,doc" + ]); + + + if($request->get('type') === 'page') + { + $request->validate([ + "id" => "required|exists:circle_xo_docs_pages,id", + ]); + } + else if($request->get('type') === 'doc') + { + $request->validate([ + "id" => "required|exists:circle_xo_docs,id", + ]); + } + + $model = $request->get('type') === 'doc' ? \Modules\CircleDocs\App\Models\CircleXoDoc::find($request->id) : \Modules\CircleDocs\App\Models\CircleXoDocsPage::find($request->id); + auth('accounts')->user()->hasLiked($model) ? auth('accounts')->user()->unlike($model) : auth('accounts')->user()->like($model); + + $request->get('type') === 'doc' ? $account = $model->account : $account = $model->doc->account; + if($account->id !== auth('accounts')->user()->id) { + $account->notifyDB( + message: __(auth('accounts')->user()->username . " " . __('is like your docs page') . ' ' . $request->get('type') === 'doc' ? $model->name : $model->title), + title: __('New Like'), + url: url(auth('accounts')->user()->username) + ); + } + + Toast::success(__('Liked successfully'))->autoDismiss(2); + return back(); + + } + + /** + * @param Request $request + * @return View|JsonResponse + */ + public function index(Request $request): View|JsonResponse + { + return Tomato::index( + request: $request, + model: $this->model, + view: 'circle-docs::docs.index', + table: \Modules\CircleDocs\App\Tables\CircleXoDocTable::class + ); + } + + /** + * @param Request $request + * @return JsonResponse + */ + public function api(Request $request): JsonResponse + { + return Tomato::json( + request: $request, + model: \Modules\CircleDocs\App\Models\CircleXoDoc::class, + ); + } + + /** + * @return View + */ + public function create(): View + { + return Tomato::create( + view: 'circle-docs::docs.create', + ); + } + + /** + * @param \Modules\CircleDocs\App\Http\Requests\CircleXoDoc\CircleXoDocStoreRequest $request + * @return RedirectResponse|JsonResponse + */ + public function store(\Modules\CircleDocs\App\Http\Requests\CircleXoDoc\CircleXoDocStoreRequest $request): RedirectResponse|JsonResponse + { + $request->merge([ + 'account_id' => auth('accounts')->user()->id, + ]); + + $response = Tomato::store( + request: $request, + model: \Modules\CircleDocs\App\Models\CircleXoDoc::class, + message: __('Doc saved successfully'), + redirect: 'profile.docs.index', + hasMedia: true, + collection: [ + 'icon' => false, + 'cover' => false, + ] + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return $response->redirect; + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDoc $model + * @return View|JsonResponse|RedirectResponse + */ + public function show(\Modules\CircleDocs\App\Models\CircleXoDoc $model, Request $request): View|JsonResponse|RedirectResponse + { + return Tomato::get( + model: $model, + view: 'circle-docs::docs.show', + hasMedia: true, + collection: [ + 'icon' => false, + 'cover' => false, + ] + ); + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDoc $model + * @return View + */ + public function edit(\Modules\CircleDocs\App\Models\CircleXoDoc $model): View + { + return Tomato::get( + model: $model, + view: 'circle-docs::docs.edit', + hasMedia: true, + collection: [ + 'icon' => false, + 'cover' => false, + ] + ); + } + + /** + * @param \Modules\CircleDocs\App\Http\Requests\CircleXoDoc\CircleXoDocUpdateRequest $request + * @param \Modules\CircleDocs\App\Models\CircleXoDoc $model + * @return RedirectResponse|JsonResponse + */ + public function update(\Modules\CircleDocs\App\Http\Requests\CircleXoDoc\CircleXoDocUpdateRequest $request, \Modules\CircleDocs\App\Models\CircleXoDoc $model): RedirectResponse|JsonResponse + { + $response = Tomato::update( + request: $request, + model: $model, + message: __('Doc updated successfully'), + redirect: 'profile.docs.index', + hasMedia: true, + collection: [ + 'icon' => false, + 'cover' => false, + ] + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return $response->redirect; + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDoc $model + * @return RedirectResponse|JsonResponse + */ + public function destroy(\Modules\CircleDocs\App\Models\CircleXoDoc $model): RedirectResponse|JsonResponse + { + $response = Tomato::destroy( + model: $model, + message: __('Doc deleted successfully'), + redirect: 'profile.docs.index', + hasMedia: true, + collection: [ + 'icon' => false, + 'cover' => false, + ] + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return $response->redirect; + } +} diff --git a/Modules/CircleDocs/App/Http/Controllers/CircleXoDocsPageController.php b/Modules/CircleDocs/App/Http/Controllers/CircleXoDocsPageController.php new file mode 100644 index 0000000..c62817a --- /dev/null +++ b/Modules/CircleDocs/App/Http/Controllers/CircleXoDocsPageController.php @@ -0,0 +1,180 @@ +model = \Modules\CircleDocs\App\Models\CircleXoDocsPage::class; + } + + /** + * @param Request $request + * @return View|JsonResponse + */ + public function index(Request $request): View|JsonResponse + { + return Tomato::index( + request: $request, + model: $this->model, + view: 'circle-docs::docs-pages.index', + table: \Modules\CircleDocs\App\Tables\CircleXoDocsPageTable::class + ); + } + + /** + * @param Request $request + * @return JsonResponse + */ + public function api(Request $request): JsonResponse + { + return Tomato::json( + request: $request, + model: \Modules\CircleDocs\App\Models\CircleXoDocsPage::class, + ); + } + + /** + * @return View + */ + public function create(Request $request): View + { + $request->validate([ + "doc_id" => [ "required",function ($attribute, $value, $fail) use ($request) { + $exists = CircleXoDoc::query() + ->where('account_id', auth('accounts')->user()->id) + ->where('id', $request->get('doc_id')) + ->first(); + + if(!$exists){ + $fail('The '.$attribute.' is not exists or it is not yours.'); + } + }], + ]); + + $doc = CircleXoDoc::find($request->get('doc_id')); + + return Tomato::create( + view: 'circle-docs::docs-pages.create', + data: [ + 'doc' => $doc, + ] + ); + } + + /** + * @param \Modules\CircleDocs\App\Http\Requests\CircleXoDocsPage\CircleXoDocsPageStoreRequest $request + * @return RedirectResponse|JsonResponse + */ + public function store(\Modules\CircleDocs\App\Http\Requests\CircleXoDocsPage\CircleXoDocsPageStoreRequest $request): RedirectResponse|JsonResponse + { + $response = Tomato::store( + request: $request, + model: \Modules\CircleDocs\App\Models\CircleXoDocsPage::class, + message: __('CircleXoDocsPage updated successfully'), + redirect: 'profile.docs-pages.index', + hasMedia: true, + collection: [ + 'cover' => false + ] + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return redirect()->route('profile.docs-pages.show', $response->record->id); + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDocsPage $model + * @return View|JsonResponse + */ + public function show(\Modules\CircleDocs\App\Models\CircleXoDocsPage $model): View|JsonResponse + { + return Tomato::get( + model: $model, + view: 'circle-docs::docs-pages.show', + hasMedia: true, + collection: [ + 'cover' => false + ] + ); + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDocsPage $model + * @return View + */ + public function edit(\Modules\CircleDocs\App\Models\CircleXoDocsPage $model): View + { + return Tomato::get( + model: $model, + view: 'circle-docs::docs-pages.edit', + hasMedia: true, + collection: [ + 'cover' => false + ] + ); + } + + /** + * @param \Modules\CircleDocs\App\Http\Requests\CircleXoDocsPage\CircleXoDocsPageUpdateRequest $request + * @param \Modules\CircleDocs\App\Models\CircleXoDocsPage $model + * @return RedirectResponse|JsonResponse + */ + public function update(\Modules\CircleDocs\App\Http\Requests\CircleXoDocsPage\CircleXoDocsPageUpdateRequest $request, \Modules\CircleDocs\App\Models\CircleXoDocsPage $model): RedirectResponse|JsonResponse + { + $response = Tomato::update( + request: $request, + model: $model, + message: __('CircleXoDocsPage updated successfully'), + redirect: 'profile.docs-pages.index', + hasMedia: true, + collection: [ + 'cover' => false + ] + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return redirect()->route('profile.docs-pages.show', $response->record->id); + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDocsPage $model + * @return RedirectResponse|JsonResponse + */ + public function destroy(\Modules\CircleDocs\App\Models\CircleXoDocsPage $model): RedirectResponse|JsonResponse + { + $doc = $model->doc->id; + $response = Tomato::destroy( + model: $model, + message: __('CircleXoDocsPage deleted successfully'), + redirect: 'profile.docs-pages.index', + hasMedia: true, + collection: [ + 'cover' => false + ] + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return redirect()->route('profile.docs.show', $doc->id); + } +} diff --git a/Modules/CircleDocs/App/Http/Controllers/CircleXoDocsPagesMetaController.php b/Modules/CircleDocs/App/Http/Controllers/CircleXoDocsPagesMetaController.php new file mode 100644 index 0000000..8f95869 --- /dev/null +++ b/Modules/CircleDocs/App/Http/Controllers/CircleXoDocsPagesMetaController.php @@ -0,0 +1,152 @@ +model = \Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta::class; + } + + /** + * @param Request $request + * @return View|JsonResponse + */ + public function index(Request $request): View|JsonResponse + { + return Tomato::index( + request: $request, + model: $this->model, + view: 'circledocs::circle-xo-docs-pages-metas.index', + table: \Modules\CircleDocs\App\Tables\CircleXoDocsPagesMetaTable::class + ); + } + + /** + * @param Request $request + * @return JsonResponse + */ + public function api(Request $request): JsonResponse + { + return Tomato::json( + request: $request, + model: \Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta::class, + ); + } + + /** + * @return View + */ + public function create(): View + { + return Tomato::create( + view: 'circledocs::circle-xo-docs-pages-metas.create', + ); + } + + /** + * @param Request $request + * @return RedirectResponse|JsonResponse + */ + public function store(Request $request): RedirectResponse|JsonResponse + { + $response = Tomato::store( + request: $request, + model: \Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta::class, + validation: [ + 'key' => 'required|max:255|string', + 'value' => 'nullable', + 'type' => 'nullable|max:255|string', + 'docs_page_id' => 'required|exists:circle_xo_docs_pages,id' + ], + message: __('CircleXoDocsPagesMeta updated successfully'), + redirect: 'admin.circle-xo-docs-pages-metas.index', + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return $response->redirect; + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta $model + * @return View|JsonResponse + */ + public function show(\Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta $model): View|JsonResponse + { + return Tomato::get( + model: $model, + view: 'circledocs::circle-xo-docs-pages-metas.show', + ); + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta $model + * @return View + */ + public function edit(\Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta $model): View + { + return Tomato::get( + model: $model, + view: 'circledocs::circle-xo-docs-pages-metas.edit', + ); + } + + /** + * @param Request $request + * @param \Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta $model + * @return RedirectResponse|JsonResponse + */ + public function update(Request $request, \Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta $model): RedirectResponse|JsonResponse + { + $response = Tomato::update( + request: $request, + model: $model, + validation: [ + 'key' => 'sometimes|max:255|string', + 'value' => 'nullable', + 'type' => 'nullable|max:255|string', + 'docs_page_id' => 'sometimes|exists:circle_xo_docs_pages,id' + ], + message: __('CircleXoDocsPagesMeta updated successfully'), + redirect: 'admin.circle-xo-docs-pages-metas.index', + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return $response->redirect; + } + + /** + * @param \Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta $model + * @return RedirectResponse|JsonResponse + */ + public function destroy(\Modules\CircleDocs\App\Models\CircleXoDocsPagesMeta $model): RedirectResponse|JsonResponse + { + $response = Tomato::destroy( + model: $model, + message: __('CircleXoDocsPagesMeta deleted successfully'), + redirect: 'admin.circle-xo-docs-pages-metas.index', + ); + + if($response instanceof JsonResponse){ + return $response; + } + + return $response->redirect; + } +} diff --git a/Modules/CircleDocs/App/Http/Requests/.gitkeep b/Modules/CircleDocs/App/Http/Requests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Http/Requests/CircleXoDoc/.gitkeep b/Modules/CircleDocs/App/Http/Requests/CircleXoDoc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Http/Requests/CircleXoDoc/CircleXoDocStoreRequest.php b/Modules/CircleDocs/App/Http/Requests/CircleXoDoc/CircleXoDocStoreRequest.php new file mode 100644 index 0000000..7dab856 --- /dev/null +++ b/Modules/CircleDocs/App/Http/Requests/CircleXoDoc/CircleXoDocStoreRequest.php @@ -0,0 +1,49 @@ + + */ + public function rules() + { + return [ + 'icon' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048', + 'cover' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048', + 'name' => 'required|max:255|string', + 'package' => ['required','max:255','string','regex:/\w*$/', function ($attribute, $value, $fail) { + $exists = CircleXoDoc::query() + ->where('account_id', auth('accounts')->user()->id) + ->where('package', $value) + ->first(); + + if($exists){ + $fail('The '.$attribute.' is already in use.'); + } + }], + 'about' => 'nullable', + 'repository' => 'nullable|max:255|string', + 'branch' => 'nullable|max:255|string', + 'readme' => 'nullable', + 'is_active' => 'nullable', + 'is_public' => 'nullable' + ]; + } +} diff --git a/Modules/CircleDocs/App/Http/Requests/CircleXoDoc/CircleXoDocUpdateRequest.php b/Modules/CircleDocs/App/Http/Requests/CircleXoDoc/CircleXoDocUpdateRequest.php new file mode 100644 index 0000000..75782b4 --- /dev/null +++ b/Modules/CircleDocs/App/Http/Requests/CircleXoDoc/CircleXoDocUpdateRequest.php @@ -0,0 +1,50 @@ + + */ + public function rules() + { + return [ + 'icon' => 'sometimes|image|mimes:jpeg,png,jpg,gif,svg|max:2048', + 'cover' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048', + 'name' => 'sometimes|max:255|string', + 'package' => ['sometimes','max:255','string', 'regex:/\w*$/', function ($attribute, $value, $fail) { + $exists = CircleXoDoc::query() + ->where('account_id', auth('accounts')->user()->id) + ->where('package', $value) + ->where('id', '!=', $this->model['id']) + ->first(); + + if($exists){ + $fail('The '.$attribute.' is already in use.'); + } + }], + 'about' => 'nullable', + 'repository' => 'nullable|max:255|string', + 'branch' => 'nullable|max:255|string', + 'readme' => 'nullable', + 'is_active' => 'nullable', + 'is_public' => 'nullable', + ]; + } +} diff --git a/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPage/.gitkeep b/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPage/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPage/CircleXoDocsPageStoreRequest.php b/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPage/CircleXoDocsPageStoreRequest.php new file mode 100644 index 0000000..4383de8 --- /dev/null +++ b/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPage/CircleXoDocsPageStoreRequest.php @@ -0,0 +1,38 @@ + + */ + public function rules() + { + return [ + 'cover' => 'nullable|image|max:2048|mimes:jpeg,jpg,png,gif,webp,svg', + 'title' => 'required|max:255|string', + 'description' => 'nullable|max:255|string', + 'body' => 'required', + 'parent_id' => 'nullable', + 'icon' => 'nullable|max:255|string', + 'color' => 'nullable|max:255|string', + 'slug' => 'nullable|max:255|string', + 'doc_id' => 'required|exists:circle_xo_docs,id' + ]; + } +} diff --git a/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPage/CircleXoDocsPageUpdateRequest.php b/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPage/CircleXoDocsPageUpdateRequest.php new file mode 100644 index 0000000..ff8cc84 --- /dev/null +++ b/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPage/CircleXoDocsPageUpdateRequest.php @@ -0,0 +1,38 @@ + + */ + public function rules() + { + return [ + 'cover' => 'nullable|image|max:2048|mimes:jpeg,jpg,png,gif,webp,svg', + 'title' => 'sometimes|max:255|string', + 'description' => 'nullable|max:255|string', + 'body' => 'sometimes', + 'parent_id' => 'nullable', + 'icon' => 'nullable|max:255|string', + 'color' => 'nullable|max:255|string', + 'slug' => 'nullable|max:255|string', + 'doc_id' => 'sometimes|exists:circle_xo_docs,id' + ]; + } +} diff --git a/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPagesMeta/.gitkeep b/Modules/CircleDocs/App/Http/Requests/CircleXoDocsPagesMeta/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Models/.gitkeep b/Modules/CircleDocs/App/Models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Models/CircleXoDoc.php b/Modules/CircleDocs/App/Models/CircleXoDoc.php new file mode 100644 index 0000000..3b8641c --- /dev/null +++ b/Modules/CircleDocs/App/Models/CircleXoDoc.php @@ -0,0 +1,61 @@ + 'boolean', + 'is_public' => 'boolean' + ]; + + + + public function account() + { + return $this->belongsTo(\App\Models\Account::class); + } + + public function pages() + { + return $this->hasMany(\Modules\CircleDocs\App\Models\CircleXoDocsPage::class, 'doc_id', 'id'); + } +} diff --git a/Modules/CircleDocs/App/Models/CircleXoDocsPage.php b/Modules/CircleDocs/App/Models/CircleXoDocsPage.php new file mode 100644 index 0000000..0cd091d --- /dev/null +++ b/Modules/CircleDocs/App/Models/CircleXoDocsPage.php @@ -0,0 +1,59 @@ +with('doc'); + } + + public function searchableAs(): string + { + return $this->doc->id.'_title_body_index'; + } + + public function doc() + { + return $this->belongsTo(\Modules\CircleDocs\App\Models\CircleXoDoc::class, 'doc_id', 'id'); + } +} diff --git a/Modules/CircleDocs/App/Models/CircleXoDocsPagesMeta.php b/Modules/CircleDocs/App/Models/CircleXoDocsPagesMeta.php new file mode 100644 index 0000000..58f486c --- /dev/null +++ b/Modules/CircleDocs/App/Models/CircleXoDocsPagesMeta.php @@ -0,0 +1,35 @@ + 'json' + ]; + + public function docsPage() + { + return $this->belongsTo(\Modules\CircleDocs\App\Models\CircleXoDocsPage); + } +} diff --git a/Modules/CircleDocs/App/Providers/.gitkeep b/Modules/CircleDocs/App/Providers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Providers/CircleDocsServiceProvider.php b/Modules/CircleDocs/App/Providers/CircleDocsServiceProvider.php new file mode 100644 index 0000000..21bddbe --- /dev/null +++ b/Modules/CircleDocs/App/Providers/CircleDocsServiceProvider.php @@ -0,0 +1,125 @@ +registerCommands(); + $this->registerCommandSchedules(); + $this->registerTranslations(); + $this->registerConfig(); + $this->registerViews(); + $this->loadMigrationsFrom(module_path($this->moduleName, 'Database/migrations')); + + CircleXoSlots::sideMenu()->register('circle-docs::side-menu'); + CircleXoSlots::profileFilterSlider()->register('circle-docs::menu'); + CircleXoSlots::profileDropdown()->register('circle-docs::dropdown'); + + + } + + /** + * Register the service provider. + */ + public function register(): void + { + $this->app->register(RouteServiceProvider::class); + } + + /** + * Register commands in the format of Command::class + */ + protected function registerCommands(): void + { + $this->commands([ + CircleDocsInstall::class + ]); + } + + /** + * Register command Schedules. + */ + protected function registerCommandSchedules(): void + { + // $this->app->booted(function () { + // $schedule = $this->app->make(Schedule::class); + // $schedule->command('inspire')->hourly(); + // }); + } + + /** + * Register translations. + */ + public function registerTranslations(): void + { + $langPath = resource_path('lang/modules/'.$this->moduleNameLower); + + if (is_dir($langPath)) { + $this->loadTranslationsFrom($langPath, $this->moduleNameLower); + $this->loadJsonTranslationsFrom($langPath); + } else { + $this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower); + $this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang')); + } + } + + /** + * Register config. + */ + protected function registerConfig(): void + { + $this->publishes([module_path($this->moduleName, 'config/config.php') => config_path($this->moduleNameLower.'.php')], 'config'); + $this->mergeConfigFrom(module_path($this->moduleName, 'config/config.php'), $this->moduleNameLower); + } + + /** + * Register views. + */ + public function registerViews(): void + { + $viewPath = resource_path('views/modules/'.$this->moduleNameLower); + $sourcePath = module_path($this->moduleName, 'resources/views'); + + $this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower.'-module-views']); + + $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower); + + $componentNamespace = str_replace('/', '\\', config('modules.namespace').'\\'.$this->moduleName.'\\'.config('modules.paths.generator.component-class.path')); + Blade::componentNamespace($componentNamespace, $this->moduleNameLower); + } + + /** + * Get the services provided by the provider. + */ + public function provides(): array + { + return []; + } + + private function getPublishableViewPaths(): array + { + $paths = []; + foreach (config('view.paths') as $path) { + if (is_dir($path.'/modules/'.$this->moduleNameLower)) { + $paths[] = $path.'/modules/'.$this->moduleNameLower; + } + } + + return $paths; + } +} diff --git a/Modules/CircleDocs/App/Providers/RouteServiceProvider.php b/Modules/CircleDocs/App/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..619cdfc --- /dev/null +++ b/Modules/CircleDocs/App/Providers/RouteServiceProvider.php @@ -0,0 +1,59 @@ +mapApiRoutes(); + + $this->mapWebRoutes(); + } + + /** + * Define the "web" routes for the application. + * + * These routes all receive session state, CSRF protection, etc. + */ + protected function mapWebRoutes(): void + { + Route::middleware('web') + ->namespace($this->moduleNamespace) + ->group(module_path('CircleDocs', '/routes/web.php')); + } + + /** + * Define the "api" routes for the application. + * + * These routes are typically stateless. + */ + protected function mapApiRoutes(): void + { + Route::prefix('api') + ->middleware('api') + ->namespace($this->moduleNamespace) + ->group(module_path('CircleDocs', '/routes/api.php')); + } +} diff --git a/Modules/CircleDocs/App/Tables/.gitkeep b/Modules/CircleDocs/App/Tables/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/Tables/CircleXoDocTable.php b/Modules/CircleDocs/App/Tables/CircleXoDocTable.php new file mode 100644 index 0000000..e2676cd --- /dev/null +++ b/Modules/CircleDocs/App/Tables/CircleXoDocTable.php @@ -0,0 +1,124 @@ +query = \Modules\CircleDocs\App\Models\CircleXoDoc::query(); + } + } + + /** + * Determine if the user is authorized to perform bulk actions and exports. + * + * @return bool + */ + public function authorize(Request $request) + { + return true; + } + + /** + * The resource or query builder. + * + * @return mixed + */ + public function for() + { + return $this->query; + } + + /** + * Configure the given SpladeTable. + * + * @param \ProtoneMedia\Splade\SpladeTable $table + * @return void + */ + public function configure(SpladeTable $table) + { + $table + ->withGlobalSearch( + label: trans('tomato-admin::global.search'), + columns: ['id','name','package',] + ) + ->bulkAction( + label: trans('tomato-admin::global.crud.delete'), + each: fn (\Modules\CircleDocs\App\Models\CircleXoDoc $model) => $model->delete(), + after: fn () => Toast::danger(__('CircleXoDoc Has Been Deleted'))->autoDismiss(2), + confirm: true + ) + ->defaultSort('id', 'desc') + ->column( + key: 'id', + label: __('Id'), + sortable: true + ) + ->column( + key: 'name', + label: __('Name'), + sortable: true + ) + ->column( + key: 'package', + label: __('Package'), + sortable: true + ) + ->column( + key: 'about', + label: __('About'), + sortable: true + ) + ->column( + key: 'repository', + label: __('Repository'), + sortable: true + ) + ->column( + key: 'branch', + label: __('Branch'), + sortable: true + ) + ->column( + key: 'readme', + label: __('Readme'), + sortable: true + ) + ->column( + key: 'is_active', + label: __('Is active'), + sortable: true + ) + ->column( + key: 'is_public', + label: __('Is public'), + sortable: true + ) + ->column( + key: 'group', + label: __('Group'), + sortable: true + ) + ->column( + key: 'account_id', + label: __('Account id'), + sortable: true + ) + ->column(key: 'actions',label: trans('tomato-admin::global.crud.actions')) + ->export() + ->paginate(10); + } +} diff --git a/Modules/CircleDocs/App/Tables/CircleXoDocsPageTable.php b/Modules/CircleDocs/App/Tables/CircleXoDocsPageTable.php new file mode 100644 index 0000000..68bdea2 --- /dev/null +++ b/Modules/CircleDocs/App/Tables/CircleXoDocsPageTable.php @@ -0,0 +1,114 @@ +query = \Modules\CircleDocs\App\Models\CircleXoDocsPage::query(); + } + } + + /** + * Determine if the user is authorized to perform bulk actions and exports. + * + * @return bool + */ + public function authorize(Request $request) + { + return true; + } + + /** + * The resource or query builder. + * + * @return mixed + */ + public function for() + { + return $this->query; + } + + /** + * Configure the given SpladeTable. + * + * @param \ProtoneMedia\Splade\SpladeTable $table + * @return void + */ + public function configure(SpladeTable $table) + { + $table + ->withGlobalSearch( + label: trans('tomato-admin::global.search'), + columns: ['id',] + ) + ->bulkAction( + label: trans('tomato-admin::global.crud.delete'), + each: fn (\Modules\CircleDocs\App\Models\CircleXoDocsPage $model) => $model->delete(), + after: fn () => Toast::danger(__('CircleXoDocsPage Has Been Deleted'))->autoDismiss(2), + confirm: true + ) + ->defaultSort('id', 'desc') + ->column( + key: 'id', + label: __('Id'), + sortable: true + ) + ->column( + key: 'title', + label: __('Title'), + sortable: true + ) + ->column( + key: 'description', + label: __('Description'), + sortable: true + ) + ->column( + key: 'body', + label: __('Body'), + sortable: true + ) + ->column( + key: 'parent_id', + label: __('Parent id'), + sortable: true + ) + ->column( + key: 'icon', + label: __('Icon'), + sortable: true + ) + ->column( + key: 'color', + label: __('Color'), + sortable: true + ) + ->column( + key: 'slug', + label: __('Slug'), + sortable: true + ) + ->column( + key: 'doc_id', + label: __('Doc id'), + sortable: true + ) + ->column(key: 'actions',label: trans('tomato-admin::global.crud.actions')) + ->export() + ->paginate(10); + } +} diff --git a/Modules/CircleDocs/App/resources/.gitkeep b/Modules/CircleDocs/App/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/App/resources/CircleXoDocsPagesResource.php b/Modules/CircleDocs/App/resources/CircleXoDocsPagesResource.php new file mode 100644 index 0000000..e3d96f2 --- /dev/null +++ b/Modules/CircleDocs/App/resources/CircleXoDocsPagesResource.php @@ -0,0 +1,30 @@ + $this->title, + 'description' => $this->description, + 'body' => $this->body, + 'parent_id' => $this->parent_id, + 'icon' => $this->icon, + 'color' => $this->color, + 'slug' => $this->slug, + 'doc' => $this->id, + + ]; + } +} diff --git a/Modules/CircleDocs/App/resources/CircleXoDocsResource.php b/Modules/CircleDocs/App/resources/CircleXoDocsResource.php new file mode 100644 index 0000000..a557e6f --- /dev/null +++ b/Modules/CircleDocs/App/resources/CircleXoDocsResource.php @@ -0,0 +1,32 @@ + $this->name, + 'package' => $this->package, + 'about' => $this->about, + 'repository' => $this->repository, + 'branch' => $this->branch, + 'readme' => $this->readme, + 'is_active' => $this->is_active, + 'is_public' => $this->is_public, + 'group' => $this->group, + 'account' => $this->id, + + ]; + } +} diff --git a/Modules/CircleDocs/CHANGELOG.md b/Modules/CircleDocs/CHANGELOG.md new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/Database/Seeders/.gitkeep b/Modules/CircleDocs/Database/Seeders/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/Database/Seeders/CircleDocsDatabaseSeeder.php b/Modules/CircleDocs/Database/Seeders/CircleDocsDatabaseSeeder.php new file mode 100644 index 0000000..6eac3a7 --- /dev/null +++ b/Modules/CircleDocs/Database/Seeders/CircleDocsDatabaseSeeder.php @@ -0,0 +1,16 @@ +call([]); + } +} diff --git a/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1010_create_circle_xo_docs_table.php b/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1010_create_circle_xo_docs_table.php new file mode 100644 index 0000000..256b6ed --- /dev/null +++ b/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1010_create_circle_xo_docs_table.php @@ -0,0 +1,37 @@ +id(); + $table->string("name")->index(); + $table->string("package")->unique()->index(); + $table->text("about")->nullable(); + $table->string("repository")->nullable(); + $table->string("branch")->nullable(); + $table->longText("readme")->nullable(); + $table->boolean("is_active")->default(false)->nullable(); + $table->boolean("is_public")->default(false)->nullable(); + $table->foreignId("account_id")->references('id')->on('accounts')->onDelete('cascade'); + $table->timestamps(); + + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('circle_xo_docs'); + } +}; diff --git a/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1212_create_circle_xo_docs_pages_table.php b/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1212_create_circle_xo_docs_pages_table.php new file mode 100644 index 0000000..c2c4d3a --- /dev/null +++ b/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1212_create_circle_xo_docs_pages_table.php @@ -0,0 +1,36 @@ +id(); + $table->string("title")->index(); + $table->string("description")->nullable(); + $table->longText("body"); + $table->bigInteger("parent_id")->nullable()->unsigned(); + $table->string("icon")->nullable(); + $table->string("color")->nullable(); + $table->string("slug")->nullable()->index(); + $table->foreignId("doc_id")->references('id')->on('circle_xo_docs')->onDelete('cascade'); + $table->string("group")->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('circle_xo_docs_pages'); + } +}; diff --git a/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1313_create_circle_xo_docs_pages_metas_table.php b/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1313_create_circle_xo_docs_pages_metas_table.php new file mode 100644 index 0000000..699b501 --- /dev/null +++ b/Modules/CircleDocs/Database/migrations/2024_03_31_11_0303_1313_create_circle_xo_docs_pages_metas_table.php @@ -0,0 +1,32 @@ +id(); + $table->string("key")->index(); + $table->json("value")->nullable(); + $table->string("type")->default('text')->nullable(); + $table->foreignId("docs_page_id")->references('id')->on('circle_xo_docs_pages')->onDelete('cascade'); + $table->timestamps(); + + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('circle_xo_docs_pages_metas'); + } +}; diff --git a/Modules/CircleDocs/LICENSE.md b/Modules/CircleDocs/LICENSE.md new file mode 100644 index 0000000..a77082f --- /dev/null +++ b/Modules/CircleDocs/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Fady Mondy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Modules/CircleDocs/README.md b/Modules/CircleDocs/README.md new file mode 100644 index 0000000..469e80c --- /dev/null +++ b/Modules/CircleDocs/README.md @@ -0,0 +1,31 @@ +![Screenshot](https://github.com/tomatophp/circle-docs-module/blob/master/art/cover.png) + +# Circle Docs + +Create and share, search in your docs using markdown editor and GitHub integration + +## Installation + +```bash +composer require tomatophp/circle-docs-module +``` + +## Support + +you can join our discord server to get support [TomatoPHP](https://discord.gg/Xqmt35Uh) + +## Docs + +you can check docs of this package on [Docs](https://docs.tomatophp.com/plugins/tomato-themes) + +## Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. + +## Security + +Please see [SECURITY](SECURITY.md) for more information about security. + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/Modules/CircleDocs/SECURITY.md b/Modules/CircleDocs/SECURITY.md new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/art/cover.png b/Modules/CircleDocs/art/cover.png new file mode 100644 index 0000000..dc517e1 Binary files /dev/null and b/Modules/CircleDocs/art/cover.png differ diff --git a/Modules/CircleDocs/art/logo.png b/Modules/CircleDocs/art/logo.png new file mode 100644 index 0000000..7638513 Binary files /dev/null and b/Modules/CircleDocs/art/logo.png differ diff --git a/Modules/CircleDocs/composer.json b/Modules/CircleDocs/composer.json new file mode 100644 index 0000000..69f75ba --- /dev/null +++ b/Modules/CircleDocs/composer.json @@ -0,0 +1,51 @@ +{ + "name": "tomatophp/circle-docs-module", + "type": "laravel-module", + "description": "Create and share, search in your docs using markdown editor and GitHub integration", + "license": "MIT", + "keywords": [ + "laravel", + "module", + "circle", + "docs", + "markdown", + "editor", + "github", + "integration" + ], + "authors": [ + { + "name": "Fady Mondy", + "email": "info@3x1.io" + } + ], + "extra": { + "laravel": { + "providers": [], + "aliases": { + + } + } + }, + "autoload": { + "psr-4": { + "Modules\\CircleDocs\\": "", + "Modules\\CircleDocs\\App\\": "app/", + "Modules\\CircleDocs\\Database\\Factories\\": "database/factories/", + "Modules\\CircleDocs\\Database\\Seeders\\": "database/seeders/" + } + }, + "autoload-dev": { + "psr-4": { + "Modules\\CircleDocs\\Tests\\": "tests/" + } + }, + "require": { + "php": "^8.1|^8.2", + "tomatophp/tomato-admin": "^1.2", + "tomatophp/tomato-plugins": "^1.2", + "tomatophp/console-helpers": "^1.1", + "joshbrw/laravel-module-installer": "^2.0", + "nwidart/laravel-modules": "^10.0" + } +} diff --git a/Modules/CircleDocs/config/.gitkeep b/Modules/CircleDocs/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/config/config.php b/Modules/CircleDocs/config/config.php new file mode 100644 index 0000000..4b0cc03 --- /dev/null +++ b/Modules/CircleDocs/config/config.php @@ -0,0 +1,5 @@ + 'CircleDocs', +]; diff --git a/Modules/CircleDocs/module.json b/Modules/CircleDocs/module.json new file mode 100644 index 0000000..d0c006f --- /dev/null +++ b/Modules/CircleDocs/module.json @@ -0,0 +1,27 @@ +{ + "name": "CircleDocs", + "alias": "circle-docs", + "description": { + "ar": "Create and share, search in your docs using markdown editor and GitHub integration", + "en": "Create and share, search in your docs using markdown editor and GitHub integration", + "gr": "Create and share, search in your docs using markdown editor and GitHub integration", + "sp": "Create and share, search in your docs using markdown editor and GitHub integration" + }, + "keywords": [], + "priority": 0, + "providers": [ + "Modules\\CircleDocs\\App\\Providers\\CircleDocsServiceProvider" + ], + "files": [], + "title": { + "ar": "Circle Docs", + "en": "Circle Docs", + "gr": "Circle Docs", + "sp": "Circle Docs" + }, + "color": "#E84B3C", + "icon": "bx bxl-github", + "placeholder": "placeholder.webp", + "type": "plugin", + "version": "v1.0" +} diff --git a/Modules/CircleDocs/package.json b/Modules/CircleDocs/package.json new file mode 100644 index 0000000..d6fbfc8 --- /dev/null +++ b/Modules/CircleDocs/package.json @@ -0,0 +1,15 @@ +{ + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build" + }, + "devDependencies": { + "axios": "^1.1.2", + "laravel-vite-plugin": "^0.7.5", + "sass": "^1.69.5", + "postcss": "^8.3.7", + "vite": "^4.0.0" + } +} diff --git a/Modules/CircleDocs/resources/assets/js/SearchDocs.vue b/Modules/CircleDocs/resources/assets/js/SearchDocs.vue new file mode 100644 index 0000000..b2bcb4d --- /dev/null +++ b/Modules/CircleDocs/resources/assets/js/SearchDocs.vue @@ -0,0 +1,110 @@ + + + + diff --git a/Modules/CircleDocs/resources/assets/sass/app.scss b/Modules/CircleDocs/resources/assets/sass/app.scss new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/resources/views/.gitkeep b/Modules/CircleDocs/resources/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/resources/views/docs-pages/.gitkeep b/Modules/CircleDocs/resources/views/docs-pages/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/resources/views/docs-pages/create.blade.php b/Modules/CircleDocs/resources/views/docs-pages/create.blade.php new file mode 100644 index 0000000..feeef84 --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs-pages/create.blade.php @@ -0,0 +1,36 @@ +@extends('circle-docs::layouts.doc', ['model' => $doc]) + +@section('title', $doc->name) +@section('icon') + @if($doc->getMedia('icon')->first()) + avatar + @else + + @endif +@endsection + +@section('content') +
+ + + + + +
+ + +
+ + +
+ +
+ + +
+ + +
+
+
+@endsection diff --git a/Modules/CircleDocs/resources/views/docs-pages/edit.blade.php b/Modules/CircleDocs/resources/views/docs-pages/edit.blade.php new file mode 100644 index 0000000..25e0ac8 --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs-pages/edit.blade.php @@ -0,0 +1,42 @@ +@extends('circle-docs::layouts.doc', ['model' => $model->doc]) + +@section('title', $model->doc->name) +@section('icon') + @if($model->doc->getMedia('icon')->first()) + avatar + @else + + @endif +@endsection + +@section('content') +
+ + + + + +
+ + +
+ + +
+ +
+ + +
+ + + +
+
+
+@endsection diff --git a/Modules/CircleDocs/resources/views/docs-pages/index.blade.php b/Modules/CircleDocs/resources/views/docs-pages/index.blade.php new file mode 100644 index 0000000..1720729 --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs-pages/index.blade.php @@ -0,0 +1,49 @@ + + + {{ __('CircleXoDocsPage') }} + + + + {{trans('tomato-admin::global.crud.create-new')}} {{__('CircleXoDocsPage')}} + + + +
+
+ + + + + + + + + + + + + + + +
+ + + + + + + + + +
+
+
+
+
+
diff --git a/Modules/CircleDocs/resources/views/docs-pages/show.blade.php b/Modules/CircleDocs/resources/views/docs-pages/show.blade.php new file mode 100644 index 0000000..3150983 --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs-pages/show.blade.php @@ -0,0 +1,29 @@ +@extends('circle-docs::layouts.doc', ['model' => $model->doc]) + +@section('title', $model->doc->name) +@section('icon') + @if($model->doc->getMedia('icon')->first()) + avatar + @else + + @endif +@endsection + +@section('content') + @if($model->getMedia('cover')->first()) +
+ cover +
+ @endif + + +
+ + +
+@endsection diff --git a/Modules/CircleDocs/resources/views/docs/.gitkeep b/Modules/CircleDocs/resources/views/docs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/resources/views/docs/create.blade.php b/Modules/CircleDocs/resources/views/docs/create.blade.php new file mode 100644 index 0000000..d0c6d7c --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs/create.blade.php @@ -0,0 +1,23 @@ +@extends('circle-xo::layouts.app') + +@section('title', __('New Doc')) + +@section('content') + + + + + + + + + + + + +
+ + +
+
+@endsection diff --git a/Modules/CircleDocs/resources/views/docs/edit.blade.php b/Modules/CircleDocs/resources/views/docs/edit.blade.php new file mode 100644 index 0000000..a61c92b --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs/edit.blade.php @@ -0,0 +1,30 @@ +@extends('circle-xo::layouts.app') + +@section('title', __('Edit Doc') .' #'.$model->id) + +@section('content') + + + + + + + + + + + + + +
+ + + +
+
+@endsection diff --git a/Modules/CircleDocs/resources/views/docs/index.blade.php b/Modules/CircleDocs/resources/views/docs/index.blade.php new file mode 100644 index 0000000..3048232 --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs/index.blade.php @@ -0,0 +1,9 @@ +@extends('circle-docs::layouts.app') + +@section('content') +
+ + + +
+@endsection diff --git a/Modules/CircleDocs/resources/views/docs/list.blade.php b/Modules/CircleDocs/resources/views/docs/list.blade.php new file mode 100644 index 0000000..919bde9 --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs/list.blade.php @@ -0,0 +1,78 @@ +@if($table->resource->count() > 0) +
+ @if(!request()->has('page') || (request()->has('page') && request()->get('page') == 1)) +
+ +
+ +

{{__('Add Docs')}}

+
+
+
+ @endif + + @foreach($table->resource as $itemKey => $item) + @php $itemPrimaryKey = $table->findPrimaryKey($item) @endphp +
+
+ + +

{{ $item->name }}

+
+
+ #{{ $item->package }} +
+
+ {{ $item->about }} +
+
+ @if($item->is_public) + + + + + + @endif + + + + + + + + + + +
+
+ {{__('Created')}} {{ $item->created_at->diffForHumans() }} +
+
+
+ @endforeach +
+@else +
+
+ +

{{__("You don't have any docs please add one")}}

+
+ + {{__('Create Doc')}} + +
+
+
+@endif diff --git a/Modules/CircleDocs/resources/views/docs/show.blade.php b/Modules/CircleDocs/resources/views/docs/show.blade.php new file mode 100644 index 0000000..6f4a140 --- /dev/null +++ b/Modules/CircleDocs/resources/views/docs/show.blade.php @@ -0,0 +1,14 @@ +@extends('circle-docs::layouts.doc') + +@section('title', $model->name) +@section('icon') + @if($model->getMedia('icon')->first()) + avatar + @else + + @endif +@endsection + +@section('content') + +@endsection diff --git a/Modules/CircleDocs/resources/views/dropdown.blade.php b/Modules/CircleDocs/resources/views/dropdown.blade.php new file mode 100644 index 0000000..bdbe30a --- /dev/null +++ b/Modules/CircleDocs/resources/views/dropdown.blade.php @@ -0,0 +1,3 @@ +@if(has_app('circle-docs')) + +@endif diff --git a/Modules/CircleDocs/resources/views/index.blade.php b/Modules/CircleDocs/resources/views/index.blade.php new file mode 100644 index 0000000..069cea3 --- /dev/null +++ b/Modules/CircleDocs/resources/views/index.blade.php @@ -0,0 +1,86 @@ +@php + SEO::openGraphType('WebPage'); + SEO::openGraphSiteName('Docs | '. setting('site_name')); + SEO::openGraphTitle('Docs | '. setting('site_name')); + SEO::openGraphUrl(url()->current()); + SEO::openGraphImage(setting('site_profile')); + SEO::metaByProperty('og:description',setting('site_description')); + + SEO::twitterCard('summary_large_image'); + SEO::twitterTitle('Docs | '. setting('site_name')); + SEO::twitterDescription(setting('site_description')); + SEO::twitterImage(setting('site_profile')); + + SEO::canonical(url()->current()); +@endphp +@seoTitle('Docs | '. setting('site_name')) +@seoDescription(setting('site_description')) +@seoKeywords(setting('site_keywords')) + + + +
+
+
+ + {{__('Docs')}} + + +
+ + + +
+
+
+
+
+ + @if(!$docs->count()) +
+
+ +

{{__('Sorry There is not app, please change search')}}

+
+
+ @else +
+ @foreach($docs as $item) +
+
+ @if($item->getMedia('icon')->first()) +
+ avatar +
+ @else +
+
+ +
+
+ @endif + +

{{ $item->name }}

+
+
+ #{{ $item->package }} +
+
+ {{ $item->about }} +
+
+ {{__('Created')}} {{ $item->created_at->diffForHumans() }} +
+
+
+ @endforeach +
+ +
+ {!! $docs->links('tomato-admin::components.pagination') !!} +
+ @endif +
+
+
+
diff --git a/Modules/CircleDocs/resources/views/layouts/app.blade.php b/Modules/CircleDocs/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..ec30fd4 --- /dev/null +++ b/Modules/CircleDocs/resources/views/layouts/app.blade.php @@ -0,0 +1,7 @@ + +
+
+ @yield('content') +
+
+
diff --git a/Modules/CircleDocs/resources/views/layouts/doc.blade.php b/Modules/CircleDocs/resources/views/layouts/doc.blade.php new file mode 100644 index 0000000..48bde23 --- /dev/null +++ b/Modules/CircleDocs/resources/views/layouts/doc.blade.php @@ -0,0 +1,160 @@ + +
+
+
+
+ +
+ + + +
+
+

@yield('title')

+
+
+
+
+
+ +
+
+ +
+
+ {{__('Search On Docs')}} +
+
+ +
+
+
+
+
+ +
+ @yield('content') +
+
+ +
+
+
+ +
+
+ +
+
+

{{ __('Add Page') }}

+
+
+
+ +
+
+ +
+
+

{{ __('Overview') }}

+
+
+
+ + @php + $groups = \Modules\CircleDocs\App\Models\CircleXoDocsPage::query()->where('doc_id', $model->id)->groupBy('group')->get(); + @endphp + + @foreach($groups as $group) + @php + $menu = \Modules\CircleDocs\App\Models\CircleXoDocsPage::query()->where('group', $group->group); + $menu->where('doc_id', $model->id); + $menu = $menu->get(); + @endphp + @if($group->group && !request()->has('search')) +
+

{{ $group->group }}

+
+ @endif + @foreach($menu as $page) + +
+
+ +
+
+

{{ $page->title }}

+
+
+
+ @endforeach + @endforeach +
+
+
+
+ + + {{__('Docs Search')}} + + + +
diff --git a/Modules/CircleDocs/resources/views/layouts/parts/sidebar.blade.php b/Modules/CircleDocs/resources/views/layouts/parts/sidebar.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/resources/views/menu.blade.php b/Modules/CircleDocs/resources/views/menu.blade.php new file mode 100644 index 0000000..8bd3a00 --- /dev/null +++ b/Modules/CircleDocs/resources/views/menu.blade.php @@ -0,0 +1,27 @@ +@php +$username = str(url()->current())->explode('@')->last(); +if($username !== url()->current()){ + $account = str($username)->explode('/')->first(); +} +else { + $account = null; +} +@endphp +@if($account) + +
+ +
+
+ +
+
+
+ {{ __('Docs') }} +
+ +
+
+@endif diff --git a/Modules/CircleDocs/resources/views/profile.blade.php b/Modules/CircleDocs/resources/views/profile.blade.php new file mode 100644 index 0000000..f876e73 --- /dev/null +++ b/Modules/CircleDocs/resources/views/profile.blade.php @@ -0,0 +1,49 @@ + +
+ + +
+ + @if($docs->count() > 0) +
+ @foreach($docs as $itemKey => $item) +
+
+ @if($item->getMedia('icon')->first()) +
+ avatar +
+ @else +
+
+ +
+
+ @endif + +

{{ $item->name }}

+
+
+ #{{ $item->package }} +
+
+ {{ $item->about }} +
+
+ {{__('Created')}} {{ $item->created_at->diffForHumans() }} +
+
+
+ @endforeach +
+ @else +
+
+ +

{{__("Sorry this account don't have any docs")}}

+
+
+ @endif +
+
+
diff --git a/Modules/CircleDocs/resources/views/show.blade.php b/Modules/CircleDocs/resources/views/show.blade.php new file mode 100644 index 0000000..61516b1 --- /dev/null +++ b/Modules/CircleDocs/resources/views/show.blade.php @@ -0,0 +1,248 @@ + +
+
+
+
+ +
+ + + +
+
+

{{$doc->name}}

+
+
+
+
+
+ +
+
+ +
+
+ {{__('Search On Docs')}} +
+
+ +
+
+
+
+
+ +
+ @if(isset($currentPage)) + @if($currentPage->getMedia('cover')->first()) +
+ cover +
+ @endif + + @else + + @endif + + @if(auth('accounts')->user()) +
+
+ @if(isset($currentPage)) + @if(!auth('accounts')->user()->hasLiked($currentPage)) + + +
+
+ +
+
+
+

{{ $currentPage->likers()->count() }}

+
+
+
+
+
+ @else + + +
+
+ +
+
+

{{ $currentPage->likers()->count() }}

+
+
+
+
+ @endif + @else + @if(!auth('accounts')->user()->hasLiked($doc)) + + +
+
+ +
+
+
+

{{ $doc->likers()->count() }}

+
+
+
+
+
+ @else + + +
+
+ +
+
+

{{ $doc->likers()->count() }}

+
+
+
+
+ @endif + + @endif +
+ + @if(isset($currentPage)) +
+ + + + + + + +
+ @else +
+ + + + + + + +
+ @endif +
+ @endif + +
+
+ +
+
+
+ +
+
+ +
+
+

{{ __('Overview') }}

+
+
+
+ + @php + $groups = \Modules\CircleDocs\App\Models\CircleXoDocsPage::query()->where('doc_id', $doc->id)->groupBy('group')->get(); + @endphp + + @foreach($groups as $group) + @php + $menu = \Modules\CircleDocs\App\Models\CircleXoDocsPage::query()->where('group', $group->group); + $menu->where('doc_id', $doc->id); + $menu = $menu->get(); + @endphp + @if($group->group && !request()->has('search')) +
+

{{ $group->group }}

+
+ @endif + @foreach($menu as $page) + +
+
+ +
+
+

{{ $page->title }}

+
+
+
+ @endforeach + @endforeach +
+
+
+
+ + + + {{__('Docs Search')}} + + + +
+ + diff --git a/Modules/CircleDocs/resources/views/side-menu.blade.php b/Modules/CircleDocs/resources/views/side-menu.blade.php new file mode 100644 index 0000000..0ae1a89 --- /dev/null +++ b/Modules/CircleDocs/resources/views/side-menu.blade.php @@ -0,0 +1,5 @@ + + + {{__('Docs')}} + diff --git a/Modules/CircleDocs/routes/.gitkeep b/Modules/CircleDocs/routes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleDocs/routes/api.php b/Modules/CircleDocs/routes/api.php new file mode 100644 index 0000000..c06c272 --- /dev/null +++ b/Modules/CircleDocs/routes/api.php @@ -0,0 +1,32 @@ +name('api.')->group(function () { +// Route::get('/circle-xo-docs', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'index'])->name('circle-xo-docs.index'); +// Route::post('/circle-xo-docs', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'store'])->name('circle-xo-docs.store'); +// Route::get('/circle-xo-docs/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'show'])->name('circle-xo-docs.show'); +// Route::post('/circle-xo-docs/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'update'])->name('circle-xo-docs.update'); +// Route::delete('/circle-xo-docs/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'destroy'])->name('circle-xo-docs.destroy'); +//}); +// +//Route::middleware(['auth:sanctum'])->name('api.')->group(function () { +// Route::get('/circle-xo-docs-pages', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'index'])->name('circle-xo-docs-pages.index'); +// Route::post('/circle-xo-docs-pages', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'store'])->name('circle-xo-docs-pages.store'); +// Route::get('/circle-xo-docs-pages/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'show'])->name('circle-xo-docs-pages.show'); +// Route::post('/circle-xo-docs-pages/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'update'])->name('circle-xo-docs-pages.update'); +// Route::delete('/circle-xo-docs-pages/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'destroy'])->name('circle-xo-docs-pages.destroy'); +//}); diff --git a/Modules/CircleDocs/routes/web.php b/Modules/CircleDocs/routes/web.php new file mode 100644 index 0000000..3867e57 --- /dev/null +++ b/Modules/CircleDocs/routes/web.php @@ -0,0 +1,50 @@ +name('profile.')->group(function () { + Route::get('profile/docs', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'index'])->name('docs.index'); + Route::post('profile/docs/like', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'like'])->name('docs.like'); + Route::get('profile/docs/api', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'api'])->name('docs.api'); + Route::get('profile/docs/create', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'create'])->name('docs.create'); + Route::post('profile/docs', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'store'])->name('docs.store'); + Route::get('profile/docs/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'show'])->name('docs.show'); + Route::get('profile/docs/{model}/edit', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'edit'])->name('docs.edit'); + Route::post('profile/docs/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'update'])->name('docs.update'); + Route::delete('profile/docs/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocController::class, 'destroy'])->name('docs.destroy'); +}); + +Route::middleware(['splade', 'auth:accounts', 'app:circle-docs'])->name('profile.')->group(function () { + Route::get('profile/docs-pages', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'index'])->name('docs-pages.index'); + Route::get('profile/docs-pages/api', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'api'])->name('docs-pages.api'); + Route::get('profile/docs-pages/create', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'create'])->name('docs-pages.create'); + Route::post('profile/docs-pages', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'store'])->name('docs-pages.store'); + Route::get('profile/docs-pages/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'show'])->name('docs-pages.show'); + Route::get('profile/docs-pages/{model}/edit', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'edit'])->name('docs-pages.edit'); + Route::post('profile/docs-pages/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'update'])->name('docs-pages.update'); + Route::delete('profile/docs-pages/{model}', [\Modules\CircleDocs\App\Http\Controllers\CircleXoDocsPageController::class, 'destroy'])->name('docs-pages.destroy'); +}); + +Route::middleware(['splade'])->prefix('{username}')->name('docs.')->group(function () { + Route::get('/docs', [CircleDocsController::class, 'profile'])->name('profile'); + Route::get('/docs/{slug}', [CircleDocsController::class, 'show'])->name('show'); + Route::get('/docs/{slug}/{page}', [CircleDocsController::class, 'page'])->name('page'); +}); + +Route::middleware(['splade'])->name('docs.')->group(function () { + Route::get('/docs', [CircleDocsController::class, 'index'])->name('index'); +}); diff --git a/Modules/CircleDocs/vite.config.js b/Modules/CircleDocs/vite.config.js new file mode 100644 index 0000000..799e03d --- /dev/null +++ b/Modules/CircleDocs/vite.config.js @@ -0,0 +1,26 @@ +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; + +export default defineConfig({ + build: { + outDir: '../../public/build-circledocs', + emptyOutDir: true, + manifest: true, + }, + plugins: [ + laravel({ + publicDirectory: '../../public', + buildDirectory: 'build-circledocs', + input: [ + __dirname + '/resources/assets/sass/app.scss', + __dirname + '/resources/assets/js/app.js' + ], + refresh: true, + }), + ], +}); + +//export const paths = [ +// 'Modules/$STUDLY_NAME$/resources/assets/sass/app.scss', +// 'Modules/$STUDLY_NAME$/resources/assets/js/app.js', +//]; \ No newline at end of file diff --git a/Modules/CircleInvoices/App/Providers/CircleInvoicesServiceProvider.php b/Modules/CircleInvoices/App/Providers/CircleInvoicesServiceProvider.php index 7ad18ec..4f0da71 100644 --- a/Modules/CircleInvoices/App/Providers/CircleInvoicesServiceProvider.php +++ b/Modules/CircleInvoices/App/Providers/CircleInvoicesServiceProvider.php @@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; use Modules\CircleApps\App\Facades\CircleAppsMenu; +use Modules\CircleApps\App\Facades\CircleXoSlots; use Modules\CircleInvoices\App\Console\CircleInvoicesInstall; class CircleInvoicesServiceProvider extends ServiceProvider diff --git a/Modules/CircleNotes/App/Console/.gitkeep b/Modules/CircleNotes/App/Console/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/App/Console/CircleNotesInstall.php b/Modules/CircleNotes/App/Console/CircleNotesInstall.php new file mode 100644 index 0000000..fe9b941 --- /dev/null +++ b/Modules/CircleNotes/App/Console/CircleNotesInstall.php @@ -0,0 +1,63 @@ +info('Install App'); + $app = App::where('key', 'circle-notes')->first(); + if(!$app){ + $app = new App(); + $app->key = 'circle-notes'; + $app->name = 'Circle Notes'; + $app->description = 'Capture Notes, organize tasks and ideas easily'; + $app->is_active = true; + $app->is_free = true; + $app->status = "active"; + $app->homepage = "https://www.github.com/tomatophp/circle-notes"; + $app->github = "https://www.github.com/tomatophp/circle-notes"; + $app->docs = "https://www.github.com/tomatophp/ccircle-notes"; + $app->privacy = "https://www.github.com/tomatophp/circle-notes"; + $app->faq = "https://www.github.com/tomatophp/circle-notes"; + $app->email = "AbdelmjidDev@gmail.com"; + $app->save(); + } + $this->callSilent('optimize:clear'); + $this->artisanCommand(["migrate"]); + $this->artisanCommand(["optimize:clear"]); + $this->info('Circle Contacts App installed successfully.'); + } +} diff --git a/Modules/CircleNotes/App/Http/Controllers/.gitkeep b/Modules/CircleNotes/App/Http/Controllers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/App/Http/Controllers/CircleXoNoteController.php b/Modules/CircleNotes/App/Http/Controllers/CircleXoNoteController.php new file mode 100644 index 0000000..8f9dffd --- /dev/null +++ b/Modules/CircleNotes/App/Http/Controllers/CircleXoNoteController.php @@ -0,0 +1,153 @@ +model = CircleXoNote::class; + } + + /** + * @param Request $request + * @return View|JsonResponse + */ + public function index(Request $request): View|JsonResponse + { + $query = CircleXoNote::query(); + $query->where('account_id', auth('accounts')->user()->id); + + return Tomato::index( + request: $request, + model: $this->model, + view: 'circle-notes::notes.index', + table: \Modules\CircleNotes\App\Tables\CircleXoNoteTable::class, + query: $query + ); + } + + /** + * @return View + */ + public function create(): View + { + return Tomato::create( + view: 'circle-notes::notes.create', + ); + } + + /** + * @param CircleXoNoteStoreRequest $request + * @return RedirectResponse|JsonResponse + */ + public function store(CircleXoNoteStoreRequest $request): RedirectResponse|JsonResponse + { + $request->merge([ + "slug" => Str::random(10), + "account_id" => auth('accounts')->user()->id + ]); + + $response = Tomato::store( + request: $request, + model: CircleXoNote::class, + message: __('Note saved successfully'), + redirect: 'profile.notes.index', + ); + + if ($response instanceof JsonResponse) { + return $response; + } + + return redirect()->route('profile.notes.show', $response->record->id); + } + + /** + * @param CircleXoNote $model + * @return View|JsonResponse + */ + public function show(CircleXoNote $model): View|JsonResponse + { + if (!has_app('circle-notes', $model->account_id)) { + abort(403); + } + + return Tomato::get( + model: $model, + view: 'circle-notes::notes.show', + ); + } + + /** + * @param CircleXoNote $model + * @return View + */ + public function edit(CircleXoNote $model): View + { + if (!has_app('circle-notes', $model->account_id)) { + abort(403); + } + + return Tomato::get( + model: $model, + view: 'circle-notes::notes.edit', + ); + } + + /** + * @param CircleXoNoteUpdateRequest $request + * @param CircleXoNote $model + * @return RedirectResponse|JsonResponse + */ + public function update(CircleXoNoteUpdateRequest $request, CircleXoNote $model): RedirectResponse|JsonResponse + { + $response = Tomato::update( + request: $request, + model: $model, + message: __('Note updated successfully'), + redirect: 'profile.notes.index', + ); + + if ($response instanceof JsonResponse) { + return $response; + } + + return redirect()->route('profile.notes.show', $model->id); + } + + /** + * @param CircleXoNote $model + * @return RedirectResponse|JsonResponse + */ + public function destroy(CircleXoNote $model): RedirectResponse|JsonResponse + { + if (!has_app('circle-notes', $model->account_id)) { + abort(403); + } + + $response = Tomato::destroy( + model: $model, + message: __('Note deleted successfully'), + redirect: 'profile.notes.index', + ); + + if ($response instanceof JsonResponse) { + return $response; + } + + return redirect()->route('profile.notes.index'); + } +} diff --git a/Modules/CircleNotes/App/Http/Controllers/CircleXoNoteShareController.php b/Modules/CircleNotes/App/Http/Controllers/CircleXoNoteShareController.php new file mode 100644 index 0000000..1d497cd --- /dev/null +++ b/Modules/CircleNotes/App/Http/Controllers/CircleXoNoteShareController.php @@ -0,0 +1,77 @@ +account_id)) { + abort(403); + } + + return Tomato::get( + model: $model, + view: 'circle-notes::notes.share', + ); + } + + + public function showShareLink($username, $slug) + { + $note = CircleXoNote::where('slug', $slug)->firstOrFail(); + if($note->is_public) { + $account = Account::where('username', $username)->firstOrFail(); + + return view('circle-notes::notes.share_page', compact('note', 'account')); + } + else { + abort(404); + } + } + + public function generateOneTimeLink(CircleXoNote $model) + { + $token = Str::random(10); + + if(!$model->links()->count()){ + CircleXoNoteLink::create([ + 'note_id' => $model->id, + 'token' => $token + ]); + + Toast::success(__('Generate one time link successfully'))->autoDismiss(2); + } + else { + Toast::danger(__('One time link already generated'))->autoDismiss(2); + } + + + return back(); + } + + public function showShareOneTimeLink($username, $token) + { + $noteLink = CircleXoNoteLink::where('token', $token)->firstOrFail(); + $note = $noteLink->note; + + $account = Account::where('username', $username)->firstOrFail(); + + // Remove the token once it's been used + $noteLink->delete(); + + return view('circle-notes::notes.share_page', compact('note', 'account')); + } +} diff --git a/Modules/CircleNotes/App/Http/Requests/CircleXoNote/CircleXoNoteStoreRequest.php b/Modules/CircleNotes/App/Http/Requests/CircleXoNote/CircleXoNoteStoreRequest.php new file mode 100644 index 0000000..b7d9898 --- /dev/null +++ b/Modules/CircleNotes/App/Http/Requests/CircleXoNote/CircleXoNoteStoreRequest.php @@ -0,0 +1,32 @@ + + */ + public function rules() + { + return [ + 'title' => 'nullable|max:255|string', + 'content' => 'required|string', + 'is_public' => 'required|boolean', + ]; + } +} diff --git a/Modules/CircleNotes/App/Http/Requests/CircleXoNote/CircleXoNoteUpdateRequest.php b/Modules/CircleNotes/App/Http/Requests/CircleXoNote/CircleXoNoteUpdateRequest.php new file mode 100644 index 0000000..b95ae5a --- /dev/null +++ b/Modules/CircleNotes/App/Http/Requests/CircleXoNote/CircleXoNoteUpdateRequest.php @@ -0,0 +1,32 @@ +model['account_id']); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'title' => 'nullable|max:255|string', + 'content' => 'required|string', + 'is_public' => 'sometimes|boolean', + ]; + } +} diff --git a/Modules/CircleNotes/App/Models/CircleXoNote.php b/Modules/CircleNotes/App/Models/CircleXoNote.php new file mode 100644 index 0000000..e84b58d --- /dev/null +++ b/Modules/CircleNotes/App/Models/CircleXoNote.php @@ -0,0 +1,44 @@ + 'boolean' + ]; + + public function account() + { + return $this->belongsTo(\App\Models\Account::class); + } + + public function links() + { + return $this->hasMany(CircleXoNoteLink::class, 'note_id'); + } + +} diff --git a/Modules/CircleNotes/App/Models/CircleXoNoteLink.php b/Modules/CircleNotes/App/Models/CircleXoNoteLink.php new file mode 100644 index 0000000..32dab07 --- /dev/null +++ b/Modules/CircleNotes/App/Models/CircleXoNoteLink.php @@ -0,0 +1,29 @@ +belongsTo(CircleXoNote::class, 'note_id'); + } +} diff --git a/Modules/CircleNotes/App/Providers/.gitkeep b/Modules/CircleNotes/App/Providers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/App/Providers/CircleNotesServiceProvider.php b/Modules/CircleNotes/App/Providers/CircleNotesServiceProvider.php new file mode 100644 index 0000000..e738a32 --- /dev/null +++ b/Modules/CircleNotes/App/Providers/CircleNotesServiceProvider.php @@ -0,0 +1,127 @@ +registerCommands(); + $this->registerCommandSchedules(); + $this->registerTranslations(); + $this->registerConfig(); + $this->registerViews(); + $this->loadMigrationsFrom(module_path($this->moduleName, 'Database/migrations')); + + CircleAppsMenu::register([ + Menu::make() + ->group('circle-notes') + ->label(__('Notes')) + ->icon('bx bxs-note') + ->route('profile.notes.index') + ]); + } + + /** + * Register the service provider. + */ + public function register(): void + { + $this->app->register(RouteServiceProvider::class); + } + + /** + * Register commands in the format of Command::class + */ + protected function registerCommands(): void + { + $this->commands([ + \Modules\CircleNotes\App\Console\CircleNotesInstall::class, + ]); + } + + /** + * Register command Schedules. + */ + protected function registerCommandSchedules(): void + { + // $this->app->booted(function () { + // $schedule = $this->app->make(Schedule::class); + // $schedule->command('inspire')->hourly(); + // }); + } + + /** + * Register translations. + */ + public function registerTranslations(): void + { + $langPath = resource_path('lang/modules/'.$this->moduleNameLower); + + if (is_dir($langPath)) { + $this->loadTranslationsFrom($langPath, $this->moduleNameLower); + $this->loadJsonTranslationsFrom($langPath); + } else { + $this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower); + $this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang')); + } + } + + /** + * Register config. + */ + protected function registerConfig(): void + { + $this->publishes([module_path($this->moduleName, 'config/config.php') => config_path($this->moduleNameLower.'.php')], 'config'); + $this->mergeConfigFrom(module_path($this->moduleName, 'config/config.php'), $this->moduleNameLower); + } + + /** + * Register views. + */ + public function registerViews(): void + { + $viewPath = resource_path('views/modules/'.$this->moduleNameLower); + $sourcePath = module_path($this->moduleName, 'resources/views'); + + $this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower.'-module-views']); + + $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower); + + $componentNamespace = str_replace('/', '\\', config('modules.namespace').'\\'.$this->moduleName.'\\'.config('modules.paths.generator.component-class.path')); + Blade::componentNamespace($componentNamespace, $this->moduleNameLower); + } + + /** + * Get the services provided by the provider. + */ + public function provides(): array + { + return []; + } + + private function getPublishableViewPaths(): array + { + $paths = []; + foreach (config('view.paths') as $path) { + if (is_dir($path.'/modules/'.$this->moduleNameLower)) { + $paths[] = $path.'/modules/'.$this->moduleNameLower; + } + } + + return $paths; + } +} diff --git a/Modules/CircleNotes/App/Providers/RouteServiceProvider.php b/Modules/CircleNotes/App/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..0480964 --- /dev/null +++ b/Modules/CircleNotes/App/Providers/RouteServiceProvider.php @@ -0,0 +1,59 @@ +mapApiRoutes(); + + $this->mapWebRoutes(); + } + + /** + * Define the "web" routes for the application. + * + * These routes all receive session state, CSRF protection, etc. + */ + protected function mapWebRoutes(): void + { + Route::middleware('web') + ->namespace($this->moduleNamespace) + ->group(module_path('CircleNotes', '/routes/web.php')); + } + + /** + * Define the "api" routes for the application. + * + * These routes are typically stateless. + */ + protected function mapApiRoutes(): void + { + Route::prefix('api') + ->middleware('api') + ->namespace($this->moduleNamespace) + ->group(module_path('CircleNotes', '/routes/api.php')); + } +} diff --git a/Modules/CircleNotes/App/Tables/CircleXoNoteTable.php b/Modules/CircleNotes/App/Tables/CircleXoNoteTable.php new file mode 100644 index 0000000..d835e1e --- /dev/null +++ b/Modules/CircleNotes/App/Tables/CircleXoNoteTable.php @@ -0,0 +1,89 @@ +query = \Modules\CircleNotes\App\Models\CircleXoNote::query(); + } + } + + /** + * Determine if the user is authorized to perform bulk actions and exports. + * + * @return bool + */ + public function authorize(Request $request) + { + return true; + } + + /** + * The resource or query builder. + * + * @return mixed + */ + public function for() + { + return $this->query; + } + + /** + * Configure the given SpladeTable. + * + * @param \ProtoneMedia\Splade\SpladeTable $table + * @return void + */ + public function configure(SpladeTable $table) + { + $table + ->withGlobalSearch( + label: trans('tomato-admin::global.search'), + columns: ['id','name','email','phone'] + ) + ->bulkAction( + label: trans('tomato-admin::global.crud.delete'), + each: function(\Modules\CircleNotes\App\Models\CircleXoNote $model){ + $model->delete(); + }, + after: fn () => Toast::danger(__('Note Has Been Deleted'))->autoDismiss(2), + confirm: true + ) + ->defaultSort('id', 'desc') + ->column( + key: 'id', + label: __('Id'), + canBeHidden: false, + sortable: true, + + ) + ->column( + key: 'title', + label: __('Title'), + canBeHidden: false, + sortable: true, + ) + ->column( + key: 'content', + label: __('Content'), + canBeHidden: false, + sortable: true + ) + ->export() + ->paginate(8); + } +} diff --git a/Modules/CircleNotes/CHANGELOG.md b/Modules/CircleNotes/CHANGELOG.md new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/Database/Seeders/.gitkeep b/Modules/CircleNotes/Database/Seeders/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/Database/Seeders/CircleNotesDatabaseSeeder.php b/Modules/CircleNotes/Database/Seeders/CircleNotesDatabaseSeeder.php new file mode 100644 index 0000000..daebc3c --- /dev/null +++ b/Modules/CircleNotes/Database/Seeders/CircleNotesDatabaseSeeder.php @@ -0,0 +1,16 @@ +call([]); + } +} diff --git a/Modules/CircleNotes/Database/migrations/2024_03_31_185249_create_circle_xo_notes_table.php b/Modules/CircleNotes/Database/migrations/2024_03_31_185249_create_circle_xo_notes_table.php new file mode 100644 index 0000000..bdd02e6 --- /dev/null +++ b/Modules/CircleNotes/Database/migrations/2024_03_31_185249_create_circle_xo_notes_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('title')->nullable(); + $table->string('slug')->unique(); + $table->text('content')->nullable(); + $table->foreignId("account_id")->references('id')->on('accounts')->onDelete('cascade'); + $table->boolean('is_public')->default(false)->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('circle_xo_notes'); + } +}; diff --git a/Modules/CircleNotes/Database/migrations/2024_03_31_211654_create_circle_xo_note_links_table.php b/Modules/CircleNotes/Database/migrations/2024_03_31_211654_create_circle_xo_note_links_table.php new file mode 100644 index 0000000..370b9fb --- /dev/null +++ b/Modules/CircleNotes/Database/migrations/2024_03_31_211654_create_circle_xo_note_links_table.php @@ -0,0 +1,29 @@ +id(); + $table->foreignId("note_id")->references('id')->on('circle_xo_notes')->onDelete('cascade'); + $table->string('token')->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('circle_xo_note_links'); + } +}; diff --git a/Modules/CircleNotes/LICENSE.md b/Modules/CircleNotes/LICENSE.md new file mode 100644 index 0000000..a77082f --- /dev/null +++ b/Modules/CircleNotes/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Fady Mondy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Modules/CircleNotes/README.md b/Modules/CircleNotes/README.md new file mode 100644 index 0000000..d50d7e2 --- /dev/null +++ b/Modules/CircleNotes/README.md @@ -0,0 +1,31 @@ +![Screenshot](https://github.com/tomatophp/circle-notes-module/blob/master/art/cover.png) + +# Circle Notes + +Capture Notes, organize tasks and ideas easily. + +## Installation + +```bash +composer require tomatophp/circle-notes-module +``` + +## Support + +you can join our discord server to get support [TomatoPHP](https://discord.gg/Xqmt35Uh) + +## Docs + +you can check docs of this package on [Docs](https://github.com/tomatophp/circle-notes-module) + +## Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. + +## Security + +Please see [SECURITY](SECURITY.md) for more information about security. + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/Modules/CircleNotes/SECURITY.md b/Modules/CircleNotes/SECURITY.md new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/art/cover.png b/Modules/CircleNotes/art/cover.png new file mode 100644 index 0000000..2689aa3 Binary files /dev/null and b/Modules/CircleNotes/art/cover.png differ diff --git a/Modules/CircleNotes/art/logo.png b/Modules/CircleNotes/art/logo.png new file mode 100644 index 0000000..eecbd3d Binary files /dev/null and b/Modules/CircleNotes/art/logo.png differ diff --git a/Modules/CircleNotes/composer.json b/Modules/CircleNotes/composer.json new file mode 100644 index 0000000..72892ac --- /dev/null +++ b/Modules/CircleNotes/composer.json @@ -0,0 +1,49 @@ +{ + "name": "tomatophp/circle-notes-module", + "type": "laravel-module", + "description": "Capture Notes, organize tasks and ideas easily", + "license": "MIT", + "keywords": [ + "laravel", + "module", + "notes", + "profile", + "circlexo", + "tomatophp" + ], + "authors": [ + { + "name": "Abdelmjid Saber", + "email": "AbdelmjidDev@gmail.com" + } + ], + "extra": { + "laravel": { + "providers": [], + "aliases": { + + } + } + }, + "autoload": { + "psr-4": { + "Modules\\CircleNotes\\": "", + "Modules\\CircleNotes\\App\\": "app/", + "Modules\\CircleNotes\\Database\\Factories\\": "database/factories/", + "Modules\\CircleNotes\\Database\\Seeders\\": "database/seeders/" + } + }, + "autoload-dev": { + "psr-4": { + "Modules\\CircleNotes\\Tests\\": "tests/" + } + }, + "require": { + "php": "^8.1|^8.2", + "tomatophp/tomato-admin": "^1.2", + "tomatophp/tomato-plugins": "^1.2", + "tomatophp/console-helpers": "^1.1", + "joshbrw/laravel-module-installer": "^2.0", + "nwidart/laravel-modules": "^10.0" + } +} diff --git a/Modules/CircleNotes/config/.gitkeep b/Modules/CircleNotes/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/config/config.php b/Modules/CircleNotes/config/config.php new file mode 100644 index 0000000..1eb9d85 --- /dev/null +++ b/Modules/CircleNotes/config/config.php @@ -0,0 +1,5 @@ + 'CircleNotes', +]; diff --git a/Modules/CircleNotes/module.json b/Modules/CircleNotes/module.json new file mode 100644 index 0000000..2ca78bc --- /dev/null +++ b/Modules/CircleNotes/module.json @@ -0,0 +1,27 @@ +{ + "name": "CircleNotes", + "alias": "circle-notes", + "description": { + "ar": "Capture Notes, organize tasks and ideas easily", + "en": "Capture Notes, organize tasks and ideas easily", + "gr": "Capture Notes, organize tasks and ideas easily", + "sp": "Capture Notes, organize tasks and ideas easily" + }, + "keywords": [], + "priority": 0, + "providers": [ + "Modules\\CircleNotes\\App\\Providers\\CircleNotesServiceProvider" + ], + "files": [], + "title": { + "ar": "Circle Notes", + "en": "Circle Notes", + "gr": "Circle Notes", + "sp": "Circle Notes" + }, + "color": "#fbbc04", + "icon": "bx bxs-note", + "placeholder": "placeholder.webp", + "type": "plugin", + "version": "v1.0" +} \ No newline at end of file diff --git a/Modules/CircleNotes/package.json b/Modules/CircleNotes/package.json new file mode 100644 index 0000000..d6fbfc8 --- /dev/null +++ b/Modules/CircleNotes/package.json @@ -0,0 +1,15 @@ +{ + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build" + }, + "devDependencies": { + "axios": "^1.1.2", + "laravel-vite-plugin": "^0.7.5", + "sass": "^1.69.5", + "postcss": "^8.3.7", + "vite": "^4.0.0" + } +} diff --git a/Modules/CircleNotes/resources/assets/js/app.js b/Modules/CircleNotes/resources/assets/js/app.js new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/resources/assets/sass/app.scss b/Modules/CircleNotes/resources/assets/sass/app.scss new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/resources/views/.gitkeep b/Modules/CircleNotes/resources/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/resources/views/notes/create.blade.php b/Modules/CircleNotes/resources/views/notes/create.blade.php new file mode 100644 index 0000000..a87739f --- /dev/null +++ b/Modules/CircleNotes/resources/views/notes/create.blade.php @@ -0,0 +1,16 @@ +@extends('circle-xo::layouts.app') + +@section('title', __('New Note')) + +@section('content') + + + + + +
+ + +
+
+@endsection diff --git a/Modules/CircleNotes/resources/views/notes/edit.blade.php b/Modules/CircleNotes/resources/views/notes/edit.blade.php new file mode 100644 index 0000000..fc8ec63 --- /dev/null +++ b/Modules/CircleNotes/resources/views/notes/edit.blade.php @@ -0,0 +1,22 @@ +@extends('circle-xo::layouts.app') + +@section('title', __('Edit Note') .' #' . $model->id ) + +@section('content') + + + + + +
+ + + +
+
+@endsection diff --git a/Modules/CircleNotes/resources/views/notes/index.blade.php b/Modules/CircleNotes/resources/views/notes/index.blade.php new file mode 100644 index 0000000..30863f6 --- /dev/null +++ b/Modules/CircleNotes/resources/views/notes/index.blade.php @@ -0,0 +1,9 @@ + +
+
+ + + +
+
+
diff --git a/Modules/CircleNotes/resources/views/notes/list.blade.php b/Modules/CircleNotes/resources/views/notes/list.blade.php new file mode 100644 index 0000000..43f19d4 --- /dev/null +++ b/Modules/CircleNotes/resources/views/notes/list.blade.php @@ -0,0 +1,47 @@ +@if($table->resource->count() > 0) +
+ @if(!request()->has('page') || (request()->has('page') && request()->get('page') == 1)) +
+ +
+ +

{{__('Add Note')}}

+
+
+
+ @endif + @foreach($table->resource as $itemKey => $item) + @php $itemPrimaryKey = $table->findPrimaryKey($item) @endphp +
+
+

{{ $item->title }}

+
+
+
+

{{ $item->updated_at->diffForHumans() }}

+
+ + + + + + +
+
+
+
+ @endforeach +
+@else +
+
+ +

{{__("You don't have any note please add one")}}

+
+ + {{__('Create Note')}} + +
+
+
+@endif diff --git a/Modules/CircleNotes/resources/views/notes/share.blade.php b/Modules/CircleNotes/resources/views/notes/share.blade.php new file mode 100644 index 0000000..c3c8c45 --- /dev/null +++ b/Modules/CircleNotes/resources/views/notes/share.blade.php @@ -0,0 +1,7 @@ +@extends('circle-xo::layouts.app') + +@section('title', __('Share') .' #' . $model->title ) + +@section('content') + +@endsection diff --git a/Modules/CircleNotes/resources/views/notes/share_page.blade.php b/Modules/CircleNotes/resources/views/notes/share_page.blade.php new file mode 100644 index 0000000..c274603 --- /dev/null +++ b/Modules/CircleNotes/resources/views/notes/share_page.blade.php @@ -0,0 +1,17 @@ + + +
+
+
+
+
+

{{ $note->title }}

+
+

+ +

+
+
+
+
+
diff --git a/Modules/CircleNotes/resources/views/notes/show.blade.php b/Modules/CircleNotes/resources/views/notes/show.blade.php new file mode 100644 index 0000000..530c621 --- /dev/null +++ b/Modules/CircleNotes/resources/views/notes/show.blade.php @@ -0,0 +1,44 @@ + +@extends('circle-xo::layouts.app') + +@section('title', $model->title) + +@section('content') + + +
+ + + + + @if($model->is_public) + + @endif + + @php + $oneTimeLinks = Modules\CircleNotes\App\Models\CircleXoNoteLink::where('note_id', $model->id)->get(); + @endphp + @foreach ($oneTimeLinks as $link) + + @endforeach + + + + +
+@endsection diff --git a/Modules/CircleNotes/routes/.gitkeep b/Modules/CircleNotes/routes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/CircleNotes/routes/api.php b/Modules/CircleNotes/routes/api.php new file mode 100644 index 0000000..4c987a2 --- /dev/null +++ b/Modules/CircleNotes/routes/api.php @@ -0,0 +1,15 @@ +name('profile.')->group(function () { + Route::get('profile/notes', [CircleXoNoteController::class, 'index'])->name('notes.index'); + Route::get('profile/notes/create', [CircleXoNoteController::class, 'create'])->name('notes.create'); + Route::post('profile/notes', [CircleXoNoteController::class, 'store'])->name('notes.store'); + Route::get('profile/notes/{model}', [CircleXoNoteController::class, 'show'])->name('notes.show'); + Route::get('profile/notes/{model}/edit', [CircleXoNoteController::class, 'edit'])->name('notes.edit'); + Route::post('profile/notes/{model}', [CircleXoNoteController::class, 'update'])->name('notes.update'); + Route::delete('profile/notes/{model}', [CircleXoNoteController::class, 'destroy'])->name('notes.destroy'); + Route::get('profile/notes/{model}/share', [CircleXoNoteShareController::class, 'share'])->name('notes.share'); + Route::post('profile/notes/{model}/generate-one-time-link', [CircleXoNoteShareController::class, 'generateOneTimeLink'])->name('notes.generate-one-time-link'); + Route::get('/{username}/notes/{slug}', [CircleXoNoteShareController::class, 'showShareLink'])->name('note.share'); + Route::get('/{username}/note/{token}', [CircleXoNoteShareController::class, 'showShareOneTimeLink'])->name('note.share-one-time-link'); +}); + +Route::middleware(['splade'])->name('profile.')->group(function () { + Route::get('/{username}/notes/{slug}', [CircleXoNoteShareController::class, 'showShareLink'])->name('note.share'); + Route::get('/{username}/note/{token}', [CircleXoNoteShareController::class, 'showShareOneTimeLink'])->name('note.share-one-time-link'); +}); diff --git a/Modules/CircleNotes/vite.config.js b/Modules/CircleNotes/vite.config.js new file mode 100644 index 0000000..78e7652 --- /dev/null +++ b/Modules/CircleNotes/vite.config.js @@ -0,0 +1,26 @@ +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; + +export default defineConfig({ + build: { + outDir: '../../public/build-circlenotes', + emptyOutDir: true, + manifest: true, + }, + plugins: [ + laravel({ + publicDirectory: '../../public', + buildDirectory: 'build-circlenotes', + input: [ + __dirname + '/resources/assets/sass/app.scss', + __dirname + '/resources/assets/js/app.js' + ], + refresh: true, + }), + ], +}); + +//export const paths = [ +// 'Modules/$STUDLY_NAME$/resources/assets/sass/app.scss', +// 'Modules/$STUDLY_NAME$/resources/assets/js/app.js', +//]; \ No newline at end of file diff --git a/Modules/CircleXO/App/Facades/CircleXo.php b/Modules/CircleXO/App/Facades/CircleXo.php new file mode 100644 index 0000000..980843f --- /dev/null +++ b/Modules/CircleXO/App/Facades/CircleXo.php @@ -0,0 +1,13 @@ +all()); + } public function provider($provider) { try { @@ -188,7 +192,7 @@ public function store(Request $request) { $request->validate([ 'name' => 'required|string|max:255', - 'username' => 'required|string|max:255|unique:accounts', + 'username' => 'required|string|max:255|regex:/\w*$/|unique:accounts', 'email' => 'required|string|email|max:255|unique:accounts', 'password' => 'required|string|min:8|confirmed', ]); diff --git a/Modules/CircleXO/App/Http/Controllers/CircleXOController.php b/Modules/CircleXO/App/Http/Controllers/CircleXOController.php index 9983f04..3a33bed 100644 --- a/Modules/CircleXO/App/Http/Controllers/CircleXOController.php +++ b/Modules/CircleXO/App/Http/Controllers/CircleXOController.php @@ -2,11 +2,13 @@ namespace Modules\CircleXO\App\Http\Controllers; +use App\Events\UserEvent; use App\Http\Controllers\Controller; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Http\Response; use App\Models\Account; +use Illuminate\Support\Facades\Event; use Modules\CircleXO\App\Models\AccountContact; use Modules\CircleXO\App\Models\AccountListing; use Modules\TomatoCms\App\Models\Page; @@ -150,13 +152,22 @@ public function send($username, Request $request) $contact->anonymous_message = $request->get('anonymous_message'); $contact->save(); - $account->notifyDB( - message: $contact->message, - title: __('You have a new message'), - url: url('profile/messages') - ); + if($request->has('contact') && $request->get('contact')){ + $account->notifyDB( + message: $contact->message, + title: __('You have a new message'), + url: url('profile/messages') + ); + } + + Event::dispatch(new UserEvent($account->id, [ + 'refresh' => true, + 'data' => $contact->toArray() + ])); - Toast::success('Message Sent Successfully')->autoDismiss(2); + if($request->has('contact') && $request->get('contact')) { + Toast::success('Message Sent Successfully')->autoDismiss(2); + } return redirect()->back(); } @@ -178,7 +189,7 @@ public function profile($username, Request $request) } $listing = $query->where('account_id', $account->id) ->where('is_active', true) - ->inRandomOrder() + ->orderBy('order', 'asc') ->paginate(12); return view('circle-xo::profile', compact('account', 'listing')); diff --git a/Modules/CircleXO/App/Http/Controllers/ProfileController.php b/Modules/CircleXO/App/Http/Controllers/ProfileController.php index 2aee1f9..190e581 100644 --- a/Modules/CircleXO/App/Http/Controllers/ProfileController.php +++ b/Modules/CircleXO/App/Http/Controllers/ProfileController.php @@ -81,7 +81,7 @@ public function messages(Request $request) $query->where('name', 'LIKE', '%'.$request->get('search').'%'); }); } - $chats = $messages->paginate(20); + $chats = $messages->paginate(2); $getSelectedChat = null; if($request->has('chat') && $request->get('chat')){ diff --git a/Modules/CircleXO/App/Http/Controllers/ProfileNotificationsController.php b/Modules/CircleXO/App/Http/Controllers/ProfileNotificationsController.php index 6af3d08..e66d87f 100644 --- a/Modules/CircleXO/App/Http/Controllers/ProfileNotificationsController.php +++ b/Modules/CircleXO/App/Http/Controllers/ProfileNotificationsController.php @@ -73,7 +73,7 @@ public function read() $notifications = UserNotification::where('model_type',config('tomato-crm.model')) ->where('model_id', auth('accounts')->user()->id) ->orderBy('id', 'desc') - ->take(10)->get(); + ->get(); foreach ($notifications as $notification){ $notification->read(); diff --git a/Modules/CircleXO/App/Providers/CircleXOServiceProvider.php b/Modules/CircleXO/App/Providers/CircleXOServiceProvider.php index cefd425..84a0768 100644 --- a/Modules/CircleXO/App/Providers/CircleXOServiceProvider.php +++ b/Modules/CircleXO/App/Providers/CircleXOServiceProvider.php @@ -5,7 +5,6 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; -use Modules\CircleApps\App\Facades\CircleAppsMenu; use Modules\TomatoThemes\App\Facades\TomatoThemes; use TomatoPHP\TomatoAdmin\Services\Contracts\Menu; @@ -35,6 +34,14 @@ public function boot(): void public function register(): void { $this->app->register(RouteServiceProvider::class); + + $this->app->bind('circle-xo', function () { + return new \Modules\CircleXO\App\Services\CircleServices(); + }); + + $this->app->bind('circle-xo-slots', function () { + return new \Modules\CircleXO\App\Services\CircleSlotServices(); + }); } public function registerComponents(): void diff --git a/Modules/CircleXO/App/Services/CircleServices.php b/Modules/CircleXO/App/Services/CircleServices.php new file mode 100644 index 0000000..5e710c1 --- /dev/null +++ b/Modules/CircleXO/App/Services/CircleServices.php @@ -0,0 +1,23 @@ +$slot){ + if($key == $place){ + $slots[] = $slot; + } + } + return $slots; + } +} diff --git a/Modules/CircleXO/App/Services/CircleSlotServices.php b/Modules/CircleXO/App/Services/CircleSlotServices.php new file mode 100644 index 0000000..516332d --- /dev/null +++ b/Modules/CircleXO/App/Services/CircleSlotServices.php @@ -0,0 +1,76 @@ +slots = []; + } + + /** + * @param string|array $menus + * @return void + */ + public function register(string|array $menus): static + { + if(is_array($menus)) { + foreach ($menus as $menu) + $this->slots[$this->place] = $menu; + } else { + $this->slots[$this->place] = $menus; + } + + return $this; + } + + public function profileFilterSlider(): static + { + $this->place = 'profile-filter-slider'; + + return $this; + } + + /** + * @return void + */ + public function sideMenu():static + { + $this->place = 'side-menu'; + return $this; + } + + + /** + * @return void + */ + public function headerMenu():static + { + $this->place = 'header-menu'; + return $this; + } + + public function profileButtons(): static + { + $this->place = 'profile-buttons'; + return $this; + } + + public function profileDropdown(): static + { + $this->place = 'profile-dropdown'; + return $this; + } + + /** + * @return array + */ + public function get(): array + { + return $this->slots; + } +} diff --git a/Modules/CircleXO/resources/views/components/header.blade.php b/Modules/CircleXO/resources/views/components/header.blade.php index dfe1e67..ac36d7e 100644 --- a/Modules/CircleXO/resources/views/components/header.blade.php +++ b/Modules/CircleXO/resources/views/components/header.blade.php @@ -1,32 +1,27 @@
+ +@if(auth('accounts')->user()) + +@endif + diff --git a/Modules/CircleXO/resources/views/components/listing-filter-item.blade.php b/Modules/CircleXO/resources/views/components/listing-filter-item.blade.php index ea3e43a..cf9e1b8 100644 --- a/Modules/CircleXO/resources/views/components/listing-filter-item.blade.php +++ b/Modules/CircleXO/resources/views/components/listing-filter-item.blade.php @@ -1,8 +1,19 @@ - +@php + $username = str(url()->current())->explode('@')->last(); + if($username !== url()->current()){ + $account = '@'.str($username)->explode('/')->first(); + } + else { + if(str(url()->current())->contains('profile')){ + $account = url('profile'); + } + $account = null; + } +@endphp @if($link)
- class([ "px-4 md:px-6 py-2 flex flex-col text-center justify-center gap-2 border border-zinc-700 rounded-lg shadow-sm", "font-bold bg-zinc-800" => (request()->has('type') && request()->get('type') === $filter), diff --git a/Modules/CircleXO/resources/views/components/listing-filters.blade.php b/Modules/CircleXO/resources/views/components/listing-filters.blade.php index 7519151..606e61d 100644 --- a/Modules/CircleXO/resources/views/components/listing-filters.blade.php +++ b/Modules/CircleXO/resources/views/components/listing-filters.blade.php @@ -2,14 +2,23 @@ + + @php $profileFilterSlider = \Modules\CircleXo\App\Facades\CircleXo::slots('profile-filter-slider'); @endphp + @foreach($profileFilterSlider as $slot) + @if(view()->exists($slot)) + @include($slot) + @endif + @endforeach
diff --git a/Modules/CircleXO/resources/views/components/menu-items.blade.php b/Modules/CircleXO/resources/views/components/menu-items.blade.php index 7264326..9b0affb 100644 --- a/Modules/CircleXO/resources/views/components/menu-items.blade.php +++ b/Modules/CircleXO/resources/views/components/menu-items.blade.php @@ -1,19 +1,23 @@ - + {{__('Home')}} - + {{__('Marketplace')}} - + {{__('Blog')}} - + {{__('Apps')}} @@ -22,24 +26,28 @@ @foreach(menu('main') as $item) @if(str($item->url)->contains('profile') && auth('accounts')->user()) @if($item->target === '_blank') - + {{$item->name}} @else - + {{$item->name}} @endif @elseif(!str($item->url)->contains('profile')) @if($item->target === '_blank') - + {{$item->name}} @else - + {{$item->name}} @@ -47,31 +55,43 @@ @endif @endforeach +@php $siteMenuSlots = \Modules\CircleXo\App\Facades\CircleXo::slots('side-menu'); @endphp +@foreach($siteMenuSlots as $slot) + @if(view()->exists($slot)) + @include($slot) + @endif +@endforeach + @if(auth('accounts')->user()) @php $providerMenus = \Modules\CircleApps\App\Facades\CircleApps::menus(); @endphp @foreach($providerMenus as $item) @if(has_app($item->group)) - + {{$item->label}} @endif @endforeach - + {{__('Profile')}} - + {{__('Logout')}} @else - + {{__('Login')}} - + {{__('Register')}} diff --git a/Modules/CircleXO/resources/views/components/profile-buttons.blade.php b/Modules/CircleXO/resources/views/components/profile-buttons.blade.php index fa3cb01..a2af11b 100644 --- a/Modules/CircleXO/resources/views/components/profile-buttons.blade.php +++ b/Modules/CircleXO/resources/views/components/profile-buttons.blade.php @@ -1,12 +1,14 @@
@if($edit) - + - + @@ -24,34 +26,41 @@ - - - - - - - @php $providerMenus = \Modules\CircleApps\App\Facades\CircleApps::menus(); @endphp + + + + - @foreach($providerMenus as $item) - @if($item->group === 'profile-dropdown' && auth('accounts')->user()) - + @php $profileDropdown = \Modules\CircleXo\App\Facades\CircleXo::slots('profile-dropdown'); @endphp + @foreach($profileDropdown as $slot) + @if(view()->exists($slot)) + @include($slot) @endif @endforeach - + @else - + @if(auth('accounts')->user()) @if(!auth('accounts')->user()->isFollowing($account)) - + @else - + @endif @endif @if($account->meta('sponsoring_link')) - + @@ -63,6 +72,13 @@ + + @php $profileButtons = \Modules\CircleXo\App\Facades\CircleXo::slots('profile-buttons'); @endphp + @foreach($profileButtons as $slot) + @if(view()->exists($slot)) + @include($slot) + @endif + @endforeach @endif
diff --git a/Modules/CircleXO/resources/views/contact.blade.php b/Modules/CircleXO/resources/views/contact.blade.php index ca93191..a3c10e7 100644 --- a/Modules/CircleXO/resources/views/contact.blade.php +++ b/Modules/CircleXO/resources/views/contact.blade.php @@ -4,6 +4,7 @@ @section('content')
+@if(auth('accounts')->user()) + +@endif diff --git a/Modules/CircleXO/resources/views/post.blade.php b/Modules/CircleXO/resources/views/post.blade.php index dcb5ef5..21b6303 100644 --- a/Modules/CircleXO/resources/views/post.blade.php +++ b/Modules/CircleXO/resources/views/post.blade.php @@ -42,7 +42,7 @@
@if(!auth('accounts')->user()->hasLiked($post)) - +
@@ -57,7 +57,7 @@ @else - +
diff --git a/Modules/CircleXO/resources/views/profile/messages.blade.php b/Modules/CircleXO/resources/views/profile/messages.blade.php index 0c26cff..ec46e33 100644 --- a/Modules/CircleXO/resources/views/profile/messages.blade.php +++ b/Modules/CircleXO/resources/views/profile/messages.blade.php @@ -17,7 +17,7 @@ class="fixed inset-0 z-20 w-full h-full filament-sidebar-close-overlay lg:hidden
-
+
@@ -43,7 +43,7 @@ class="fixed inset-0 z-20 w-full h-full filament-sidebar-close-overlay lg:hidden
-
+{{--
--}}
@@ -80,18 +80,29 @@ class="fixed inset-0 z-20 w-full h-full filament-sidebar-close-overlay lg:hidden
-
+{{--
--}}
{{ $lastMessage->sender?->name ??__('Anonymous') }}
-
Online
+{{--
Online
--}}
+ @php + $chatMessages = \Modules\CircleXO\App\Models\AccountContact::query() + ->where('account_id', auth('accounts')->user()->id) + ->where('sender_id', $lastMessage->sender_id) + ->orWhere('account_id', $lastMessage->sender_id) + ->where('sender_id', auth('accounts')->user()->id) + ->orderBy('created_at', 'desc') + ->paginate(10, '*', 'messages'); + + @endphp + {{-- chats bubble --}} -
+
@@ -106,17 +117,16 @@ class="fixed inset-0 z-20 w-full h-full filament-sidebar-close-overlay lg:hidden
-
- @php - $chatMessages = \Modules\CircleXO\App\Models\AccountContact::query() - ->where('account_id', auth('accounts')->user()->id) - ->where('sender_id', $lastMessage->sender_id) - ->orWhere('account_id', $lastMessage->sender_id) - ->where('sender_id', auth('accounts')->user()->id) - ->orderBy('created_at', 'asc') - ->get(); - @endphp + @if(!request()->has('messages') || (request()->has('messages') && request()->get('messages') != $chatMessages->lastPage())) + +
+ {{__('Load Old Messages')}} +
+
+ @endif + +
@if($chatMessages->count() < 1) @@ -125,27 +135,35 @@ class="fixed inset-0 z-20 w-full h-full filament-sidebar-close-overlay lg:hidden
@endif - @foreach($chatMessages as $chatMessage) + @foreach($chatMessages->reverse() as $chatMessage) @if($chatMessage->sender_id == auth('accounts')->user()->id) {{-- received --}} -
+
-
{{ $chatMessage->message }}
+
{{ $chatMessage->message }}
@else {{-- sent --}} -
+
-
+
                                             {{ $chatMessage->message }}
-                                        
+
@endif @endforeach + + @if(request()->has('messages') && request()->get('messages') != 1) + +
+ {{__('Load New Messages')}} +
+
+ @endif
@@ -154,7 +172,7 @@ class="fixed inset-0 z-20 w-full h-full filament-sidebar-close-overlay lg:hidden
- +