├── public
├── build
│ └── assets
│ │ ├── app-CxTZjYJl.js
│ │ ├── chart-CxTZjYJl.js
│ │ ├── table-CxTZjYJl.js
│ │ ├── theme-CxTZjYJl.js
│ │ ├── dropdown-CxTZjYJl.js
│ │ ├── editor-CxTZjYJl.js
│ │ ├── repeater-CxTZjYJl.js
│ │ └── media-manager-CxTZjYJl.js
├── favicon.ico
├── favicon.png
├── img
│ └── auth-background.png
└── fonts
│ ├── manrope-v14-latin-500.woff2
│ ├── manrope-v14-latin-600.woff2
│ ├── manrope-v14-latin-700.woff2
│ ├── manrope-v14-latin-800.woff2
│ ├── open-sans-v35-latin-700.woff2
│ ├── manrope-v14-latin-regular.woff2
│ └── open-sans-v35-latin-regular.woff2
├── resources
├── views
│ ├── table
│ │ ├── cell.blade.php
│ │ ├── table.blade.php
│ │ ├── actions.blade.php
│ │ └── column.blade.php
│ ├── fields
│ │ ├── hidden.blade.php
│ │ ├── dropdown-option.blade.php
│ │ ├── checkbox-option.blade.php
│ │ ├── panel.blade.php
│ │ ├── fieldset.blade.php
│ │ ├── editor
│ │ │ ├── media.blade.php
│ │ │ ├── history.blade.php
│ │ │ ├── blocks.blade.php
│ │ │ ├── list.blade.php
│ │ │ ├── heading.blade.php
│ │ │ └── link.blade.php
│ │ ├── textarea.blade.php
│ │ ├── repeater-table.blade.php
│ │ ├── boolean.blade.php
│ │ ├── checkbox.blade.php
│ │ ├── media.blade.php
│ │ ├── input.blade.php
│ │ ├── file.blade.php
│ │ ├── repeater.blade.php
│ │ ├── slug.blade.php
│ │ └── date.blade.php
│ ├── components
│ │ ├── icon.blade.php
│ │ ├── alert.blade.php
│ │ ├── chart.blade.php
│ │ ├── layout
│ │ │ ├── breadcrumbs.blade.php
│ │ │ ├── footer.blade.php
│ │ │ ├── sidebar-group.blade.php
│ │ │ └── theme.blade.php
│ │ └── copyable.blade.php
│ ├── partials
│ │ └── logo.blade.php
│ ├── filters
│ │ └── search.blade.php
│ ├── media
│ │ ├── filters.blade.php
│ │ ├── queued-medium.blade.php
│ │ └── medium.blade.php
│ ├── icons
│ │ ├── format-line.blade.php
│ │ ├── format-italic.blade.php
│ │ ├── chevron-down.blade.php
│ │ ├── chevron-up.blade.php
│ │ ├── minus.blade.php
│ │ ├── check.blade.php
│ │ ├── chevron-left.blade.php
│ │ ├── chevron-right.blade.php
│ │ ├── format-underline.blade.php
│ │ ├── filter.blade.php
│ │ ├── chevron-up-down.blade.php
│ │ ├── close.blade.php
│ │ ├── plus.blade.php
│ │ ├── system-mode.blade.php
│ │ ├── eye.blade.php
│ │ ├── image.blade.php
│ │ ├── download.blade.php
│ │ ├── pie-chart.blade.php
│ │ ├── trending-up.blade.php
│ │ ├── format-align-justify.blade.php
│ │ ├── trending-down.blade.php
│ │ ├── format-clear.blade.php
│ │ ├── home.blade.php
│ │ ├── star.blade.php
│ │ ├── history-do.blade.php
│ │ ├── history-undo.blade.php
│ │ ├── notifications.blade.php
│ │ ├── format-align-left.blade.php
│ │ ├── format-align-right.blade.php
│ │ ├── archive.blade.php
│ │ ├── bar-chart.blade.php
│ │ ├── format-align-center.blade.php
│ │ ├── edit.blade.php
│ │ ├── shopping-bag.blade.php
│ │ ├── clipboard.blade.php
│ │ ├── shopping-cart.blade.php
│ │ ├── users.blade.php
│ │ ├── trash.blade.php
│ │ ├── arrow-outward.blade.php
│ │ ├── format-bold.blade.php
│ │ ├── document.blade.php
│ │ ├── search.blade.php
│ │ ├── dark-mode.blade.php
│ │ ├── menu.blade.php
│ │ ├── format-highlight.blade.php
│ │ ├── format-strike.blade.php
│ │ ├── format-link.blade.php
│ │ ├── bazar-emblem.blade.php
│ │ ├── spruce-emblem.blade.php
│ │ ├── format-ordered-list.blade.php
│ │ ├── format-unlink.blade.php
│ │ ├── cone-emblem.blade.php
│ │ └── format-bullet-list.blade.php
│ ├── dashboard.blade.php
│ ├── actions
│ │ ├── actions.blade.php
│ │ └── action.blade.php
│ ├── resources
│ │ ├── index.blade.php
│ │ └── relation.blade.php
│ ├── auth
│ │ └── forgot-password.blade.php
│ └── widgets
│ │ ├── trend.blade.php
│ │ └── value.blade.php
├── sass
│ ├── component
│ │ ├── badge
│ │ │ ├── _index.scss
│ │ │ ├── _status.scss
│ │ │ └── _trending.scss
│ │ ├── form
│ │ │ ├── _btn-dropdown.scss
│ │ │ ├── _index.scss
│ │ │ └── _repeater.scss
│ │ ├── _skip-link.scss
│ │ ├── _data-group.scss
│ │ ├── _open-search.scss
│ │ ├── _or-separator.scss
│ │ ├── _pagination.scss
│ │ ├── _auth-form.scss
│ │ ├── _theme-switcher.scss
│ │ ├── _range-group.scss
│ │ ├── _notification-dot.scss
│ │ ├── _index.scss
│ │ ├── _preloader.scss
│ │ ├── _search-modal.scss
│ │ ├── _welcome-card.scss
│ │ ├── _user-menu.scss
│ │ └── _breadcrumb-list.scss
│ ├── config
│ │ ├── _styles.scss
│ │ ├── _index.scss
│ │ ├── _dark-mode.scss
│ │ └── _font.scss
│ ├── helper
│ │ ├── _index.scss
│ │ ├── _margin.scss
│ │ ├── _vertical-align.scss
│ │ └── _display.scss
│ ├── extend
│ │ ├── _index.scss
│ │ ├── _form.scss
│ │ ├── _chart.scss
│ │ ├── _progress.scss
│ │ └── _btn.scss
│ ├── layout
│ │ ├── _index.scss
│ │ ├── _container.scss
│ │ ├── _row.scss
│ │ └── _main.scss
│ ├── section
│ │ ├── _index.scss
│ │ ├── _body.scss
│ │ ├── _footer.scss
│ │ ├── _actions.scss
│ │ ├── _heading.scss
│ │ ├── _sidebar.scss
│ │ └── _header.scss
│ └── app.scss
└── js
│ ├── chart.js
│ ├── theme.js
│ ├── table.js
│ ├── repeater.js
│ └── helpers.js
├── stubs
├── placeholder.png
├── Field.stub
├── Trend.stub
├── Value.stub
├── Widget.stub
├── Action.stub
├── SelectFilter.stub
├── RootServiceProvider.stub
└── Resource.stub
├── src
├── Interfaces
│ ├── Models
│ │ ├── Event.php
│ │ ├── Setting.php
│ │ ├── Notification.php
│ │ ├── Meta.php
│ │ ├── Translation.php
│ │ ├── AuthCode.php
│ │ ├── Medium.php
│ │ └── User.php
│ ├── Settings
│ │ └── Registry.php
│ ├── Navigation
│ │ └── Registry.php
│ ├── Breadcrumbs
│ │ └── Registry.php
│ ├── Form.php
│ └── Conversion
│ │ └── Manager.php
├── Exceptions
│ ├── SaveFormDataException.php
│ ├── QueryResolutionException.php
│ └── ResourceResolutionException.php
├── Widgets
│ └── Welcome.php
├── Traits
│ ├── Makeable.php
│ ├── Filterable.php
│ ├── HasMetaData.php
│ ├── Authorizable.php
│ ├── HasRootEvents.php
│ ├── Translatable.php
│ ├── InteractsWithProxy.php
│ ├── HasMedia.php
│ ├── ResolvesWidgets.php
│ └── AsForm.php
├── Filters
│ ├── RenderableFilter.php
│ ├── SearchField.php
│ ├── MediaSearch.php
│ └── TrashStatus.php
├── Http
│ ├── Controllers
│ │ ├── Controller.php
│ │ ├── ActionController.php
│ │ ├── DashboardController.php
│ │ ├── DownloadController.php
│ │ ├── WidgetController.php
│ │ ├── RepeaterController.php
│ │ ├── MorphToController.php
│ │ └── MediaController.php
│ └── Middleware
│ │ ├── Authenticate.php
│ │ ├── TwoFactorAuthenticate.php
│ │ └── Authorize.php
├── Fields
│ ├── Color.php
│ ├── Email.php
│ ├── ID.php
│ ├── Radio.php
│ ├── Hidden.php
│ ├── HasOne.php
│ ├── MorphMany.php
│ ├── MorphOne.php
│ ├── MorphOneOrMany.php
│ ├── Range.php
│ ├── CheckboxOption.php
│ ├── HasMany.php
│ ├── Textarea.php
│ ├── Checkbox.php
│ ├── Number.php
│ └── Text.php
├── View
│ └── Components
│ │ ├── Layout
│ │ ├── Header.php
│ │ ├── Footer.php
│ │ ├── Theme.php
│ │ ├── Sidebar.php
│ │ ├── Notifications.php
│ │ ├── Breadcrumbs.php
│ │ └── SidebarGroup.php
│ │ ├── Copyable.php
│ │ ├── Chart.php
│ │ ├── Icon.php
│ │ ├── Alert.php
│ │ └── Modal.php
├── Notifications
│ ├── RootChannel.php
│ ├── ResetPassword.php
│ └── RootNotification.php
├── Actions
│ ├── SendVerificationNotification.php
│ └── SendPasswordResetNotification.php
├── Navigation
│ ├── Registry.php
│ └── Location.php
├── Listeners
│ └── FormatRootStubs.php
├── Settings
│ └── Registry.php
├── Models
│ └── Attachment.php
├── Casts
│ └── MetaValue.php
├── Console
│ └── Commands
│ │ ├── ActionMake.php
│ │ ├── ClearMedia.php
│ │ ├── Install.php
│ │ └── ClearChunks.php
├── Jobs
│ └── PerformConversions.php
├── Support
│ ├── Facades
│ │ └── Conversion.php
│ └── Copyable.php
└── Conversion
│ └── GdDriver.php
├── routes
├── api.php
└── auth.php
├── database
├── factories
│ ├── EventFactory.php
│ ├── TranslationFactory.php
│ ├── SettingFactory.php
│ ├── MetaFactory.php
│ ├── MediumFactory.php
│ ├── AuthCodeFactory.php
│ └── NotificationFactory.php
├── seeders
│ └── RootTestDataSeeder.php
└── migrations
│ ├── 2024_09_02_111321_create_root_settings_table.php
│ ├── 2024_05_14_091321_create_root_auth_codes_table.php
│ ├── 2020_07_01_000000_create_root_meta_data_table.php
│ ├── 2024_03_21_175513_create_root_events_table.php
│ ├── 2024_11_07_195330_create_root_translations_table.php
│ └── 2023_08_15_101934_create_root_notifications_table.php
└── LICENSE
/public/build/assets/app-CxTZjYJl.js:
--------------------------------------------------------------------------------
1 | import"./app-DkVGwCQq.js";
2 |
--------------------------------------------------------------------------------
/public/build/assets/chart-CxTZjYJl.js:
--------------------------------------------------------------------------------
1 | import"./app-DkVGwCQq.js";
2 |
--------------------------------------------------------------------------------
/public/build/assets/table-CxTZjYJl.js:
--------------------------------------------------------------------------------
1 | import"./app-DkVGwCQq.js";
2 |
--------------------------------------------------------------------------------
/public/build/assets/theme-CxTZjYJl.js:
--------------------------------------------------------------------------------
1 | import"./app-DkVGwCQq.js";
2 |
--------------------------------------------------------------------------------
/public/build/assets/dropdown-CxTZjYJl.js:
--------------------------------------------------------------------------------
1 | import"./app-DkVGwCQq.js";
2 |
--------------------------------------------------------------------------------
/public/build/assets/editor-CxTZjYJl.js:
--------------------------------------------------------------------------------
1 | import"./app-DkVGwCQq.js";
2 |
--------------------------------------------------------------------------------
/public/build/assets/repeater-CxTZjYJl.js:
--------------------------------------------------------------------------------
1 | import"./app-DkVGwCQq.js";
2 |
--------------------------------------------------------------------------------
/resources/views/table/cell.blade.php:
--------------------------------------------------------------------------------
1 |
{!! $formattedValue !!} |
2 |
--------------------------------------------------------------------------------
/public/build/assets/media-manager-CxTZjYJl.js:
--------------------------------------------------------------------------------
1 | import"./app-DkVGwCQq.js";
2 |
--------------------------------------------------------------------------------
/resources/views/fields/hidden.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/favicon.png
--------------------------------------------------------------------------------
/resources/sass/component/badge/_index.scss:
--------------------------------------------------------------------------------
1 | @forward 'trending';
2 | @forward 'status';
3 |
--------------------------------------------------------------------------------
/resources/views/components/icon.blade.php:
--------------------------------------------------------------------------------
1 | @include($icon, ['attributes' => $attributes])
2 |
--------------------------------------------------------------------------------
/stubs/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/stubs/placeholder.png
--------------------------------------------------------------------------------
/resources/sass/config/_styles.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | @include generate-styles;
4 |
--------------------------------------------------------------------------------
/resources/views/fields/dropdown-option.blade.php:
--------------------------------------------------------------------------------
1 | {!! $label !!}
2 |
--------------------------------------------------------------------------------
/resources/sass/helper/_index.scss:
--------------------------------------------------------------------------------
1 | @forward 'display';
2 | @forward 'margin';
3 | @forward 'vertical-align';
4 |
--------------------------------------------------------------------------------
/resources/views/components/alert.blade.php:
--------------------------------------------------------------------------------
1 | {{ $slot }}
2 |
--------------------------------------------------------------------------------
/resources/views/partials/logo.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/img/auth-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/img/auth-background.png
--------------------------------------------------------------------------------
/resources/sass/extend/_index.scss:
--------------------------------------------------------------------------------
1 | @forward 'btn';
2 | @forward 'chart';
3 | @forward 'form';
4 | @forward 'progress';
5 |
--------------------------------------------------------------------------------
/resources/sass/layout/_index.scss:
--------------------------------------------------------------------------------
1 | @forward 'container';
2 | @forward 'row';
3 | @forward 'main';
4 | @forward 'auth';
5 |
--------------------------------------------------------------------------------
/resources/sass/config/_index.scss:
--------------------------------------------------------------------------------
1 | @forward 'config';
2 | @forward 'font';
3 | @forward 'styles';
4 | @forward 'dark-mode';
5 |
--------------------------------------------------------------------------------
/public/fonts/manrope-v14-latin-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/fonts/manrope-v14-latin-500.woff2
--------------------------------------------------------------------------------
/public/fonts/manrope-v14-latin-600.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/fonts/manrope-v14-latin-600.woff2
--------------------------------------------------------------------------------
/public/fonts/manrope-v14-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/fonts/manrope-v14-latin-700.woff2
--------------------------------------------------------------------------------
/public/fonts/manrope-v14-latin-800.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/fonts/manrope-v14-latin-800.woff2
--------------------------------------------------------------------------------
/resources/sass/helper/_margin.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .m-block\:0 {
4 | margin-block: 0 !important;
5 | }
6 |
--------------------------------------------------------------------------------
/public/fonts/open-sans-v35-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/fonts/open-sans-v35-latin-700.woff2
--------------------------------------------------------------------------------
/public/fonts/manrope-v14-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/fonts/manrope-v14-latin-regular.woff2
--------------------------------------------------------------------------------
/public/fonts/open-sans-v35-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/conedevelopment/root/HEAD/public/fonts/open-sans-v35-latin-regular.woff2
--------------------------------------------------------------------------------
/resources/sass/helper/_vertical-align.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .vertical-align\:top {
4 | vertical-align: top !important;
5 | }
6 |
--------------------------------------------------------------------------------
/resources/sass/section/_index.scss:
--------------------------------------------------------------------------------
1 | @forward 'sidebar';
2 | @forward 'header';
3 | @forward 'heading';
4 | @forward 'body';
5 | @forward 'actions';
6 | @forward 'footer';
7 |
--------------------------------------------------------------------------------
/resources/sass/section/_body.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .app-body {
4 | display: flex;
5 | flex-direction: column;
6 | gap: spacer('m');
7 | }
8 |
--------------------------------------------------------------------------------
/src/Interfaces/Models/Event.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ $label }}
4 |
5 |
--------------------------------------------------------------------------------
/resources/views/filters/search.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/Interfaces/Models/Notification.php:
--------------------------------------------------------------------------------
1 |
2 | @foreach($filters as $filter)
3 | @include($filter['template'], $filter)
4 | @endforeach
5 |
6 |
--------------------------------------------------------------------------------
/resources/sass/component/form/_index.scss:
--------------------------------------------------------------------------------
1 | @forward 'btn-dropdown';
2 | @forward 'combobox';
3 | @forward 'editor';
4 | @forward 'file-group';
5 | @forward 'file-list';
6 | @forward 'repeater';
7 | @forward 'search-form';
8 |
--------------------------------------------------------------------------------
/src/Exceptions/SaveFormDataException.php:
--------------------------------------------------------------------------------
1 | {
4 | return {
5 | init() {
6 | const chart = new ApexCharts(this.$el, config);
7 |
8 | chart.render();
9 | },
10 | };
11 | });
12 |
--------------------------------------------------------------------------------
/routes/api.php:
--------------------------------------------------------------------------------
1 | except(['store']);
10 |
--------------------------------------------------------------------------------
/src/Interfaces/Settings/Registry.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/Filters/RenderableFilter.php:
--------------------------------------------------------------------------------
1 |
9 | @foreach($widgets as $widget)
10 | @include($widget['template'], $widget)
11 | @endforeach
12 |
13 | @endsection
14 |
--------------------------------------------------------------------------------
/resources/views/fields/panel.blade.php:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/Interfaces/Models/Translation.php:
--------------------------------------------------------------------------------
1 | count($request, $this->resolveQuery($request));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/stubs/Value.stub:
--------------------------------------------------------------------------------
1 | count($request, $this->resolveQuery($request));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/resources/views/components/chart.blade.php:
--------------------------------------------------------------------------------
1 | @if(! empty($config))
2 |
3 | @endif
4 |
5 | {{-- Script --}}
6 | @pushOnce('scripts')
7 | {{
8 | Vite::withEntryPoints('resources/js/chart.js')
9 | ->useBuildDirectory('vendor/root/build')
10 | ->useHotFile(public_path('vendor/root/hot'))
11 | }}
12 | @endpushOnce
13 |
--------------------------------------------------------------------------------
/resources/views/icons/format-italic.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/sass/layout/_container.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .container {
4 | --inline-size: #{config('container-inline-size', $layout)};
5 | --gap: #{get-css-variable(--container-gap)};
6 |
7 | @include layout-center(
8 | var(--gap),
9 | var(--inline-size)
10 | );
11 |
12 | &--wide {
13 | --inline-size: 100%;
14 | }
15 |
16 | &--narrow {
17 | --inline-size: 50rem;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/resources/views/fields/fieldset.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
--------------------------------------------------------------------------------
/resources/views/components/layout/breadcrumbs.blade.php:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/resources/views/icons/chevron-down.blade.php:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/resources/views/icons/chevron-up.blade.php:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/resources/views/icons/minus.blade.php:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/resources/views/icons/check.blade.php:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/resources/views/icons/chevron-left.blade.php:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/resources/views/icons/chevron-right.blade.php:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/src/Fields/Color.php:
--------------------------------------------------------------------------------
1 | type('color');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Fields/Email.php:
--------------------------------------------------------------------------------
1 | type('email');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/resources/views/icons/format-underline.blade.php:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/resources/sass/component/_or-separator.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .or-separator {
4 | align-items: center;
5 | display: flex;
6 | font-size: config('font-size-sm', $typography);
7 | gap: spacer('s');
8 | text-transform: uppercase;
9 |
10 | &::before,
11 | &::after {
12 | background-color: color('border');
13 | block-size: 1px;
14 | content: '';
15 | display: flex;
16 | inline-size: 100%;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/resources/views/components/layout/footer.blade.php:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/resources/sass/component/_pagination.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .pagination {
4 | &__links {
5 | @include clear-list;
6 | display: flex;
7 | flex-wrap: wrap;
8 | gap: spacer('xs');
9 |
10 | > * + * {
11 | margin-block-start: 0;
12 | }
13 | }
14 |
15 | [aria-current='page'] {
16 | background-color: color('primary-background', 'btn');
17 | color: color('primary-foreground', 'btn');
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/resources/views/icons/filter.blade.php:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/src/Interfaces/Navigation/Registry.php:
--------------------------------------------------------------------------------
1 | hiddenOn(['create', 'update']);
17 |
18 | $this->sortable();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/resources/sass/helper/_display.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .display {
4 | @each $name, $breakpoint in $breakpoints {
5 | @include breakpoint($name) {
6 | &--flex\:#{$name} {
7 | display: flex !important;
8 | }
9 | }
10 | }
11 |
12 | @each $name, $breakpoint in $breakpoints {
13 | @include breakpoint($name) {
14 | &--none\:#{$name} {
15 | display: none !important;
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/stubs/Widget.stub:
--------------------------------------------------------------------------------
1 | view('root::components.layout.header');
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/resources/views/icons/chevron-up-down.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/close.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/plus.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/system-mode.blade.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/resources/views/icons/eye.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/image.blade.php:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/resources/views/icons/download.blade.php:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/resources/views/icons/pie-chart.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/trending-up.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/format-align-justify.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/trending-down.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/format-clear.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/home.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/star.blade.php:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/resources/sass/component/_auth-form.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .auth-form {
4 | @include layout-stack('s');
5 | margin-block: auto;
6 |
7 | &__title {
8 | font-weight: 700;
9 | }
10 |
11 | .or-separator {
12 | margin-block-start: spacer('m');
13 | }
14 | }
15 |
16 | .form-group-stacked,
17 | .social-logins {
18 | @include layout-stack('s');
19 | }
20 |
21 | .form-label {
22 | &--space-between {
23 | display: flex;
24 | justify-content: space-between;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/resources/views/fields/editor/media.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 | @include('root::media.manager', [
12 | 'label' => $label,
13 | 'modalKey' => $modalKey,
14 | ])
15 |
16 |
--------------------------------------------------------------------------------
/resources/views/icons/history-do.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/history-undo.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/notifications.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/format-align-left.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/format-align-right.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/archive.blade.php:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/resources/views/icons/bar-chart.blade.php:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/resources/views/icons/format-align-center.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/edit.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/Fields/Radio.php:
--------------------------------------------------------------------------------
1 | class('form-check__control')
16 | ->setAttributes([
17 | 'type' => 'radio',
18 | 'name' => $this->getModelAttribute(),
19 | ]);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/resources/views/icons/shopping-bag.blade.php:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/resources/views/icons/clipboard.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/shopping-cart.blade.php:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/src/View/Components/Layout/Footer.php:
--------------------------------------------------------------------------------
1 | view('root::components.layout.footer', [
19 | 'version' => Root::VERSION,
20 | ]);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/resources/js/theme.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('alpine:init', () => {
2 | window.Alpine.data('theme', () => {
3 | return {
4 | theme: window.$cookie.get('theme', 'system'),
5 | change(theme) {
6 | document.dispatchEvent(new CustomEvent('theme:change', {
7 | detail: { theme },
8 | }));
9 |
10 | this.theme = theme;
11 |
12 | this.$root.querySelector(`.theme-switcher__${theme}-mode`).focus();
13 | },
14 | };
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/Fields/Hidden.php:
--------------------------------------------------------------------------------
1 | type('hidden');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/resources/views/fields/textarea.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | @if($invalid)
10 | {!! $error !!}
11 | @endif
12 | @if($help)
13 | {!! $help !!}
14 | @endif
15 |
16 |
--------------------------------------------------------------------------------
/resources/views/icons/users.blade.php:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/Fields/HasOne.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class HasOne extends HasOneOrMany
14 | {
15 | /**
16 | * {@inheritdoc}
17 | */
18 | public function getRelation(Model $model): EloquentRelation
19 | {
20 | return parent::getRelation($model);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Interfaces/Models/AuthCode.php:
--------------------------------------------------------------------------------
1 | route('action');
19 |
20 | return $action->perform($request);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Fields/MorphMany.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class MorphMany extends MorphOneOrMany
14 | {
15 | /**
16 | * {@inheritdoc}
17 | */
18 | public function getRelation(Model $model): EloquentRelation
19 | {
20 | return parent::getRelation($model);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/resources/sass/app.scss:
--------------------------------------------------------------------------------
1 | @forward 'config';
2 | @forward 'layout';
3 | @forward 'component';
4 | @forward 'section';
5 | @forward 'extend';
6 | @forward 'helper';
7 |
8 | @use 'sprucecss/scss/spruce' as *;
9 |
10 | :root {
11 | @include set-css-variable((
12 | --sidebar-inline-size: 20rem,
13 | --header-block-size: 4.5rem,
14 | --container-gap: spacer-clamp('m', 'l')
15 | ));
16 | }
17 |
18 | body {
19 | overflow-x: hidden;
20 | }
21 |
22 | [x-cloak] {
23 | visibility: hidden !important;
24 | }
25 |
26 | img {
27 | border-radius: config('border-radius-sm', $display);
28 | }
29 |
--------------------------------------------------------------------------------
/src/View/Components/Layout/Theme.php:
--------------------------------------------------------------------------------
1 | view('root::components.layout.theme', [
19 | 'theme' => Cookie::get('__root_theme', 'system'),
20 | ]);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/stubs/Action.stub:
--------------------------------------------------------------------------------
1 | * {
22 | pointer-events: none;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/resources/sass/extend/_form.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .form-group-stack {
4 | @include layout-stack('s');
5 |
6 | &--bordered {
7 | > * + * {
8 | border-block-start: 1px solid color('border');
9 | padding-block-start: spacer('s');
10 | }
11 | }
12 | }
13 |
14 | legend {
15 | font-family: config('font-family-heading', $typography);
16 | }
17 |
18 | .form-control[type=color] {
19 | @include set-css-variable((
20 | --border-radius: spacer-clamp('m', 'l')
21 | ));
22 | }
23 |
24 | .required-marker {
25 | color: color('danger', 'alert');
26 | }
27 |
--------------------------------------------------------------------------------
/resources/sass/config/_dark-mode.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | @include generate-color-variables(
4 | $dark-colors,
5 | ':root[data-theme-mode="dark"]'
6 | );
7 |
8 | [data-theme-mode='dark'] {
9 | color-scheme: dark;
10 |
11 | /* stylelint-disable selector-no-qualifying-type,selector-class-pattern */
12 | select.form-control:not([multiple]):not([size]),
13 | .combobox__control {
14 | @include field-icon(
15 | config('select', $form-icon, false),
16 | color('select-foreground', 'form', true, $dark-colors)
17 | );
18 | }
19 | /* stylelint-enable */
20 | }
21 |
--------------------------------------------------------------------------------
/src/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | expectsJson() ? null : URL::route('root.auth.login');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Notifications/RootChannel.php:
--------------------------------------------------------------------------------
1 | $notification::class],
18 | $notification->toRoot($notifiable)->toArray()
19 | );
20 |
21 | $notifiable->rootNotifications()->create($data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/View/Components/Layout/Sidebar.php:
--------------------------------------------------------------------------------
1 | view('root::components.layout.sidebar', [
19 | 'groups' => Root::instance()->navigation->location('sidebar')->groups(),
20 | ]);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/resources/views/components/copyable.blade.php:
--------------------------------------------------------------------------------
1 | {!! $text !!}
2 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/trash.blade.php:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/View/Components/Layout/Notifications.php:
--------------------------------------------------------------------------------
1 | view('root::components.layout.notifications', [
19 | 'url' => URL::route('root.api.notifications.index'),
20 | ]);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/resources/sass/component/_range-group.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .range-group {
4 | display: flex;
5 | flex-direction: column;
6 | gap: spacer('xxs');
7 |
8 | .form-label {
9 | align-items: center;
10 | display: flex;
11 | flex-wrap: wrap;
12 | gap: spacer('xs');
13 | justify-content: center;
14 | }
15 |
16 | &__inner {
17 | align-items: center;
18 | display: flex;
19 | gap: spacer('xs');
20 |
21 | .form-range {
22 | flex-grow: 1;
23 | margin-block-start: 0;
24 | }
25 |
26 | .form-range-control {
27 | flex-shrink: 0;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/resources/views/icons/arrow-outward.blade.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/Fields/MorphOne.php:
--------------------------------------------------------------------------------
1 |
14 | */
15 | class MorphOne extends MorphOneOrMany
16 | {
17 | /**
18 | * {@inheritdoc}
19 | */
20 | public function getRelation(Model $model): EloquentRelation
21 | {
22 | return parent::getRelation($model);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Interfaces/Breadcrumbs/Registry.php:
--------------------------------------------------------------------------------
1 | pluck('id')->toJson() }} })">
2 |
8 | @include('root::table.body')
9 |
10 |
11 | {{-- Script --}}
12 | @pushOnce('scripts')
13 | {{
14 | Vite::withEntryPoints('resources/js/table.js')
15 | ->useBuildDirectory('vendor/root/build')
16 | ->useHotFile(public_path('vendor/root/hot'))
17 | }}
18 | @endpushOnce
19 |
--------------------------------------------------------------------------------
/src/Filters/SearchField.php:
--------------------------------------------------------------------------------
1 | classList()->replace('form-control', 'search-form__control');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/resources/sass/component/badge/_status.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:color';
2 | @use 'sass:map';
3 | @use 'sprucecss/scss/spruce' as *;
4 |
5 | .status {
6 | align-items: center;
7 | display: inline-flex;
8 | gap: spacer('xs');
9 | line-height: 1;
10 | position: relative;
11 | white-space: nowrap;
12 |
13 | @each $name, $value in map.get($colors, 'alert') {
14 | &--#{$name}::before {
15 | background-color: color($name, 'alert');
16 | }
17 | }
18 |
19 | &::before {
20 | --size: 0.55em;
21 | block-size: var(--size);
22 | border-radius: 50%;
23 | content: '';
24 | flex-shrink: 0;
25 | inline-size: var(--size);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Fields/MorphOneOrMany.php:
--------------------------------------------------------------------------------
1 |
14 | */
15 | abstract class MorphOneOrMany extends HasOneOrMany
16 | {
17 | /**
18 | * {@inheritdoc}
19 | */
20 | public function getRelation(Model $model): EloquentRelation
21 | {
22 | return parent::getRelation($model);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Http/Controllers/DashboardController.php:
--------------------------------------------------------------------------------
1 | $root->widgets->map->data($request)->all(),
21 | ]);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Http/Controllers/DownloadController.php:
--------------------------------------------------------------------------------
1 | middleware('signed');
18 | }
19 |
20 | /**
21 | * Handle the incoming request.
22 | */
23 | public function __invoke(Medium $medium): BinaryFileResponse
24 | {
25 | return $medium->download();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/resources/views/icons/format-bold.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/fields/repeater-table.blade.php:
--------------------------------------------------------------------------------
1 | @if(! empty($values))
2 |
3 |
4 |
5 | @foreach($values[0] as $field)
6 | | {!! $field['label'] !!} |
7 | @endforeach
8 |
9 |
10 |
11 | @foreach($values as $value)
12 |
13 | @foreach($value as $field)
14 | | {!! $field['formattedValue'] !!} |
15 | @endforeach
16 |
17 | @endforeach
18 |
19 |
20 | @endif
21 |
--------------------------------------------------------------------------------
/src/Traits/Filterable.php:
--------------------------------------------------------------------------------
1 | except('filter') as $name => $value) {
18 | if ($this->hasNamedScope($name) && ! empty($value)) {
19 | $this->callNamedScope($name, [$query, $value]);
20 | }
21 | }
22 |
23 | return $query;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/resources/views/icons/document.blade.php:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/resources/views/fields/boolean.blade.php:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/Actions/SendVerificationNotification.php:
--------------------------------------------------------------------------------
1 | reject(static fn (User $user): bool => $user->hasVerifiedEmail())
19 | ->each(static function (User $user): void {
20 | $user->sendEmailVerificationNotification();
21 | });
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/resources/sass/component/_notification-dot.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .notification-dot {
4 | --size: 1em;
5 | background-color: color('success', 'alert');
6 | block-size: calc(var(--size) / 2);
7 | border-radius: 50%;
8 | display: inline-flex;
9 | inline-size: calc(var(--size) / 2);
10 | margin-left: 10px;
11 | position: relative;
12 |
13 | &::before {
14 | block-size: var(--size);
15 | border: 3px solid color('success', 'alert');
16 | border-radius: 50%;
17 | content: '';
18 | inline-size: var(--size);
19 | inset: calc(var(--size) / 4 * -1) auto auto calc(var(--size) / 4 * -1);
20 | opacity: 0;
21 | position: absolute;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Http/Controllers/WidgetController.php:
--------------------------------------------------------------------------------
1 | route('widget');
20 |
21 | $data = $widget->data($request);
22 |
23 | return ResponseFactory::view($data['template'], $data);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/database/factories/EventFactory.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | protected $model = Event::class;
18 |
19 | /**
20 | * Define the model's default state.
21 | */
22 | public function definition(): array
23 | {
24 | return [
25 | 'action' => 'Create',
26 | 'payload' => [],
27 | ];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/resources/js/table.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('alpine:init', () => {
2 | window.Alpine.data('table', (config) => {
3 | return {
4 | models: config.models,
5 | selection: [],
6 | selectedAllMatchingQuery: false,
7 | selectedAllModels: false,
8 | init() {
9 | this.$watch('selection', () => {
10 | this.$refs.selectCheckbox.indeterminate = this.selection.length > 0 && this.selection.length < this.models.length;
11 |
12 | this.selectedAllModels = this.selection.length > 0 && this.selection.length === this.models.length;
13 | });
14 | },
15 | };
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/src/Fields/Range.php:
--------------------------------------------------------------------------------
1 | type('range');
24 | $this->step(1);
25 | $this->min(0);
26 | $this->max(100);
27 | $this->class(['form-range', 'range-group__control']);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/database/factories/TranslationFactory.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | protected $model = Translation::class;
18 |
19 | /**
20 | * Define the model's default state.
21 | */
22 | public function definition(): array
23 | {
24 | return [
25 | 'locale' => $this->faker->locale(),
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/resources/views/fields/checkbox.blade.php:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/Traits/HasMetaData.php:
--------------------------------------------------------------------------------
1 | morphMany(Meta::getProxiedClass(), 'metable');
18 | }
19 |
20 | /**
21 | * Get the meta value of the given key.
22 | */
23 | public function metaValue(string $key, mixed $default = null): mixed
24 | {
25 | return $this->metaData->sortByDesc('created_at')->firstWhere('key', $key)?->value ?: $default;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/resources/sass/component/_index.scss:
--------------------------------------------------------------------------------
1 | @forward 'alert';
2 | @forward 'auth-form';
3 | @forward 'badge';
4 | @forward 'block-navigation';
5 | @forward 'breadcrumb-list';
6 | @forward 'card';
7 | @forward 'context-menu';
8 | @forward 'data-group';
9 | @forward 'data-table';
10 | @forward 'form';
11 | @forward 'media-uploader';
12 | @forward 'modal';
13 | @forward 'notification-dot';
14 | @forward 'notification';
15 | @forward 'open-search';
16 | @forward 'or-separator';
17 | @forward 'pagination';
18 | @forward 'preloader';
19 | @forward 'prism';
20 | @forward 'range-group';
21 | @forward 'search-modal';
22 | @forward 'skip-link';
23 | @forward 'theme-switcher';
24 | @forward 'user-menu';
25 | @forward 'welcome-card';
26 | @forward 'widget';
27 |
--------------------------------------------------------------------------------
/resources/views/icons/search.blade.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/Interfaces/Form.php:
--------------------------------------------------------------------------------
1 | locations[$name] ??= new Location($name);
22 | }
23 |
24 | /**
25 | * Get the registered. locations
26 | */
27 | public function locations(): array
28 | {
29 | return $this->locations;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/resources/views/icons/dark-mode.blade.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/database/factories/SettingFactory.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | protected $model = Setting::class;
18 |
19 | /**
20 | * Define the model's default state.
21 | */
22 | public function definition(): array
23 | {
24 | return [
25 | 'key' => $this->faker->slug(1),
26 | 'value' => mt_rand(10, 1000),
27 | ];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Listeners/FormatRootStubs.php:
--------------------------------------------------------------------------------
1 | tag === 'root-stubs') {
18 | foreach ($event->paths as $to) {
19 | $contents = file_get_contents($to);
20 |
21 | $contents = str_replace('{{ namespace }}', App::getNamespace(), $contents);
22 |
23 | file_put_contents($to, $contents);
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/database/factories/MetaFactory.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | protected $model = Meta::class;
19 |
20 | /**
21 | * Define the model's default state.
22 | */
23 | public function definition(): array
24 | {
25 | return [
26 | 'key' => Str::random(5),
27 | 'value' => Str::random(5),
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Interfaces/Conversion/Manager.php:
--------------------------------------------------------------------------------
1 | view('root::components.copyable', [
26 | 'text' => $this->text,
27 | 'value' => $this->value,
28 | ]);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/resources/views/icons/menu.blade.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/stubs/SelectFilter.stub:
--------------------------------------------------------------------------------
1 | each(static function (User $user) use ($broker): void {
22 | $user->sendPasswordResetNotification(
23 | $broker->createToken($user)
24 | );
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Notifications/ResetPassword.php:
--------------------------------------------------------------------------------
1 | $this->token,
23 | 'email' => $notifiable->getEmailForPasswordReset(),
24 | ]);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/resources/sass/component/_preloader.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .preloader--circle {
4 | --color: currentColor;
5 | --border-width: 0.25em;
6 | --size: 1.5rem;
7 | --animation-duration: 1s;
8 |
9 | block-size: var(--size);
10 | inline-size: var(--size);
11 |
12 | &::after {
13 | animation: rotation var(--animation-duration) linear infinite;
14 | block-size: var(--size);
15 | border: var(--border-width) solid var(--color);
16 | border-color: var(--color) transparent var(--color) transparent;
17 | border-radius: 50%;
18 | content: '';
19 | display: flex;
20 | inline-size: var(--size);
21 | }
22 | }
23 |
24 | @keyframes rotation {
25 | 0% { transform: rotate(0deg); }
26 | 100% { transform: rotate(360deg); }
27 | }
28 |
--------------------------------------------------------------------------------
/resources/sass/config/_font.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | @include font-face(
4 | 'Manrope',
5 | '/vendor/root/fonts/manrope-v14-latin-regular.woff2'
6 | );
7 |
8 | @include font-face(
9 | 'Manrope',
10 | '/vendor/root/fonts/manrope-v14-latin-500.woff2',
11 | 500
12 | );
13 |
14 | @include font-face(
15 | 'Manrope',
16 | '/vendor/root/fonts/manrope-v14-latin-600.woff2',
17 | 600
18 | );
19 |
20 | @include font-face(
21 | 'Manrope',
22 | '/vendor/root/fonts/manrope-v14-latin-800.woff2',
23 | 700
24 | );
25 |
26 | @include font-face(
27 | 'Open Sans',
28 | '/vendor/root/fonts/open-sans-v35-latin-regular.woff2'
29 | );
30 |
31 | @include font-face(
32 | 'Open Sans',
33 | '/vendor/root/fonts/open-sans-v35-latin-700.woff2',
34 | 700
35 | );
36 |
--------------------------------------------------------------------------------
/src/Filters/MediaSearch.php:
--------------------------------------------------------------------------------
1 | attributes = $attributes;
24 |
25 | parent::__construct(new Fields);
26 | }
27 |
28 | /**
29 | * {@inheritdoc}
30 | */
31 | public function getSearchableAttributes(): array
32 | {
33 | return array_fill_keys($this->attributes, null);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/database/seeders/RootTestDataSeeder.php:
--------------------------------------------------------------------------------
1 | seedUsers();
19 | }
20 |
21 | /**
22 | * Seed the user models.
23 | */
24 | protected function seedUsers(): void
25 | {
26 | User::proxy()->newQuery()->create([
27 | 'name' => 'Root Admin',
28 | 'email' => 'admin@root.local',
29 | 'password' => Hash::make('password'),
30 | ]);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Navigation/Location.php:
--------------------------------------------------------------------------------
1 | name = $name;
22 | }
23 |
24 | /**
25 | * Get the items by their groups.
26 | */
27 | public function groups(): array
28 | {
29 | return array_reduce($this->items, static function (array $groups, Item $item): array {
30 | $groups[$item->group ?? __('General')][] = $item;
31 |
32 | return $groups;
33 | }, []);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Notifications/RootNotification.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | public function via(object $notifiable): array
21 | {
22 | return [RootChannel::class];
23 | }
24 |
25 | /**
26 | * Get the Root Message representation of the notification.
27 | */
28 | abstract public function toRoot(object $notifiable): RootMessage;
29 | }
30 |
--------------------------------------------------------------------------------
/src/View/Components/Chart.php:
--------------------------------------------------------------------------------
1 | config = $config;
23 | }
24 |
25 | /**
26 | * Get the view / view contents that represent the component.
27 | */
28 | public function render(): View
29 | {
30 | return $this->view('root::components.chart', [
31 | 'config' => $this->config,
32 | ]);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/View/Components/Icon.php:
--------------------------------------------------------------------------------
1 | name = $name;
23 | }
24 |
25 | /**
26 | * Get the view / view contents that represent the component.
27 | */
28 | public function render(): View
29 | {
30 | return $this->view('root::components.icon', [
31 | 'icon' => sprintf('root::icons.%s', $this->name),
32 | ]);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Http/Middleware/TwoFactorAuthenticate.php:
--------------------------------------------------------------------------------
1 | user()->shouldTwoFactorAuthenticate($request)) {
22 | return Redirect::route('root.auth.two-factor.show');
23 | }
24 |
25 | return $next($request);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/resources/views/fields/editor/history.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
11 |
20 |
21 |
--------------------------------------------------------------------------------
/resources/sass/layout/_row.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .l-row {
4 | align-items: start;
5 | display: grid;
6 | gap: spacer('m');
7 | grid-template-columns: minmax(0, 1fr);
8 |
9 | &--stretch {
10 | align-items: stretch;
11 | }
12 |
13 | @each $name, $breakpoint in $breakpoints {
14 | @for $i from 1 through 4 {
15 | @include breakpoint($name) {
16 | &--column\:#{$name}\:#{$i} {
17 | grid-template-columns: repeat(#{$i}, minmax(0, 1fr));
18 | }
19 | }
20 | }
21 | }
22 |
23 | &--sidebar {
24 | @include breakpoint('lg') {
25 | grid-template-columns: minmax(0, 1fr) minmax(0, 20rem);
26 | }
27 | }
28 |
29 | &__column {
30 | display: grid;
31 | gap: spacer('m');
32 | grid-template-columns: minmax(0, 1fr);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/resources/views/fields/editor/blocks.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
10 |
19 |
20 |
--------------------------------------------------------------------------------
/resources/views/media/queued-medium.blade.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/database/migrations/2024_09_02_111321_create_root_settings_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->string('key')->unique();
19 | $table->text('value')->nullable();
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | */
27 | public function down(): void
28 | {
29 | Schema::dropIfExists('root_settings');
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/resources/sass/component/_search-modal.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .search-modal {
4 | display: flex;
5 | flex-direction: column;
6 | gap: spacer('s');
7 | }
8 |
9 | .search-results {
10 | @include scrollbar;
11 | @include clear-list;
12 | max-block-size: 20rem;
13 | overflow-y: auto;
14 | padding-inline-end: spacer('s');
15 |
16 | > li + li {
17 | border-block-start: 1px dashed color('border');
18 | margin-block-start: spacer('xs');
19 | padding-block-start: spacer('xs');
20 | }
21 | }
22 |
23 | .search-result-item {
24 | align-items: center;
25 | color: color('text');
26 | display: flex;
27 | flex-wrap: wrap;
28 | gap: spacer('xs');
29 | text-decoration: none;
30 |
31 | &__icon {
32 | --size: 1em;
33 | block-size: var(--size);
34 | color: color('primary');
35 | inline-size: var(--size);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/resources/sass/extend/_chart.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .apexcharts-legend-series {
4 | align-items: center;
5 | display: flex !important;
6 | gap: spacer('xxs');
7 | }
8 |
9 | .apexcharts-legend {
10 | display: flex;
11 | gap: spacer('s');
12 |
13 | > * {
14 | margin: 0 !important;
15 | }
16 | }
17 |
18 | .apexcharts-text,
19 | .apexcharts-legend-text {
20 | color: color('text') !important;
21 | fill: color('text');
22 | }
23 |
24 | .apexcharts-tooltip,
25 | .apexcharts-tooltip-title {
26 | background: color('background') !important;
27 | border-color: color('border') !important;
28 | }
29 |
30 | .apexcharts-tooltip-title {
31 | line-height: 1;
32 | padding-block: 0.75em !important;
33 | }
34 |
35 | .apexcharts-xaxis-tick,
36 | .apexcharts-gridline,
37 | .apexcharts-grid-borders line:last-child {
38 | stroke: color('border');
39 | }
40 |
--------------------------------------------------------------------------------
/resources/views/fields/media.blade.php:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/src/Traits/Authorizable.php:
--------------------------------------------------------------------------------
1 | authorizationResolver = $callback;
23 |
24 | return $this;
25 | }
26 |
27 | /**
28 | * Resolve the authorization.
29 | */
30 | public function authorized(Request $request, ...$parameters): bool
31 | {
32 | return is_null($this->authorizationResolver)
33 | || call_user_func_array($this->authorizationResolver, [$request, ...$parameters]);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Fields/CheckboxOption.php:
--------------------------------------------------------------------------------
1 | checked($value);
15 | }
16 |
17 | /**
18 | * Set the "selected" HTML attribute.
19 | */
20 | public function checked(bool $value = true): static
21 | {
22 | return $this->setAttribute('checked', $value);
23 | }
24 |
25 | /**
26 | * Get the array representation of the object.
27 | */
28 | public function toArray(): array
29 | {
30 | $value = parent::toArray();
31 |
32 | unset($value['selected']);
33 |
34 | return array_merge($value, ['checked' => $this->getAttribute('checked')]);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/resources/sass/layout/_main.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .l-main {
4 | display: flex;
5 | position: relative;
6 |
7 | &__sidebar {
8 | background-color: color('background');
9 | display: none;
10 | inline-size: get-css-variable(--sidebar-inline-size);
11 | inset-block: 0;
12 | inset-inline: 0 auto;
13 | position: fixed;
14 | z-index: 20;
15 |
16 | @include breakpoint('md') {
17 | display: block;
18 | }
19 |
20 | &--open {
21 | display: block;
22 | }
23 | }
24 |
25 | &__body {
26 | background-color: color('background', 'main');
27 | inline-size: 100%;
28 | min-block-size: calc(100lvh + 1rem);
29 |
30 | @include breakpoint('md') {
31 | inline-size: calc(100% - #{get-css-variable(--sidebar-inline-size)});
32 | margin-inline-start: get-css-variable(--sidebar-inline-size);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/resources/sass/section/_heading.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .app-heading {
4 | padding-block: spacer-clamp('m', 'l');
5 |
6 | &__inner {
7 | display: flex;
8 | flex-wrap: wrap;
9 | gap: spacer('s') spacer('m');
10 | justify-content: space-between;
11 |
12 | &--column {
13 | flex-direction: column;
14 | }
15 | }
16 |
17 | &__caption {
18 | @include layout-stack('xs');
19 | }
20 |
21 | &__title {
22 | font-weight: 700;
23 | }
24 |
25 | &__description {
26 | @include layout-stack('xxs');
27 | align-items: center;
28 | display: flex;
29 | flex-wrap: wrap;
30 | font-size: 1rem;
31 | gap: spacer('xs') spacer('m');
32 | }
33 |
34 | &__actions {
35 | align-items: center;
36 | display: flex;
37 | flex-wrap: wrap;
38 | gap: spacer('xs')spacer('s');
39 | justify-content: end;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/resources/views/icons/format-highlight.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/icons/format-strike.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/views/fields/input.blade.php:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/src/Http/Controllers/RepeaterController.php:
--------------------------------------------------------------------------------
1 | route('_resource');
19 |
20 | /** @var \Cone\Root\Fields\Repeater $field */
21 | $field = $request->route('field');
22 |
23 | $model = $request->filled('model')
24 | ? $resource->resolveRouteBinding($request, $request->input('model'))
25 | : $resource->getModelInstance();
26 |
27 | return new JsonResponse($field->buildOption($request, $model));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Http/Middleware/Authorize.php:
--------------------------------------------------------------------------------
1 | route($name)->authorized(
23 | $request,
24 | ...array_values(Arr::only($request->route()->parameters(), $parameters))
25 | ));
26 |
27 | return $next($request);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Traits/HasRootEvents.php:
--------------------------------------------------------------------------------
1 | morphMany(Event::getProxiedClass(), 'target');
19 | }
20 |
21 | /**
22 | * Record a new root event for the model.
23 | */
24 | public function recordRootEvent(string $action, ?User $user = null, ?array $payload = null): Event
25 | {
26 | $event = $this->rootEvents()->make([
27 | 'action' => $action,
28 | 'payload' => $payload,
29 | ]);
30 |
31 | $event->user()->associate($user)->save();
32 |
33 | return $event;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Http/Controllers/MorphToController.php:
--------------------------------------------------------------------------------
1 | route('field');
20 |
21 | $related = array_filter($params, fn (mixed $param): bool => $param instanceof Model);
22 |
23 | $related = $related[array_key_last($related)] ?? null;
24 |
25 | $data = $field->toInput($request, $related ?: $model);
26 |
27 | return ResponseFactory::view($data['template'], $data);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/View/Components/Layout/Breadcrumbs.php:
--------------------------------------------------------------------------------
1 | request = $request;
25 | }
26 |
27 | /**
28 | * Get the view / view contents that represent the component.
29 | */
30 | public function render(): View
31 | {
32 | return $this->view('root::components.layout.breadcrumbs', [
33 | 'breadcrumbs' => Root::instance()->breadcrumbs->resolve($this->request),
34 | ]);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/resources/views/icons/format-link.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/Interfaces/Models/Medium.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | class HasMany extends HasOneOrMany
15 | {
16 | /**
17 | * Create a new relation field instance.
18 | */
19 | public function __construct(string $label, Closure|string|null $modelAttribute = null, Closure|string|null $relation = null)
20 | {
21 | parent::__construct($label, $modelAttribute, $relation);
22 |
23 | $this->setAttribute('multiple', true);
24 | }
25 |
26 | /**
27 | * {@inheritdoc}
28 | */
29 | public function getRelation(Model $model): EloquentRelation
30 | {
31 | return parent::getRelation($model);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/database/migrations/2024_05_14_091321_create_root_auth_codes_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
19 | $table->integer('code')->unsigned();
20 | $table->timestamp('expires_at');
21 | $table->timestamps();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | */
28 | public function down(): void
29 | {
30 | Schema::dropIfExists('root_auth_codes');
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/resources/views/fields/file.blade.php:
--------------------------------------------------------------------------------
1 |
25 |
--------------------------------------------------------------------------------
/resources/js/repeater.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('alpine:init', () => {
2 | window.Alpine.data('repeater', (url, options = []) => {
3 | return {
4 | processing: false,
5 | options: options,
6 | add() {
7 | this.processing = true;
8 |
9 | window.$http.post(url).then((response) => {
10 | this.options.push(response.data);
11 | }).catch((error) => {
12 | //
13 | }).finally(() => {
14 | this.processing = false;
15 | });
16 | },
17 | remove(index) {
18 | this.options.splice(index, 1);
19 | },
20 | swap(from, to) {
21 | const tmp = this.options[to];
22 |
23 | this.options[to] = this.options[from];
24 |
25 | this.options[from] = tmp;
26 | },
27 | };
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/resources/views/fields/editor/list.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
11 |
20 |
21 |
--------------------------------------------------------------------------------
/resources/sass/component/badge/_trending.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:color';
2 | @use 'sprucecss/scss/spruce' as *;
3 |
4 | .trending {
5 | align-items: center;
6 | border-radius: 2rem;
7 | display: inline-flex;
8 | font-family: config('font-family-heading', $typography);
9 | font-size: config('font-size-sm', $typography);
10 | font-weight: 600;
11 | gap: spacer('xxs');
12 | line-height: 1;
13 | padding: 0.35em 0.55em;
14 |
15 | &--up {
16 | background: color.adjust(color('success', 'alert', $only-color: true), $lightness: 60%);
17 | color: color.adjust(color('success', 'alert', $only-color: true), $lightness: -7.5%);
18 | }
19 |
20 | &--down {
21 | background: color.adjust(color('danger', 'alert', $only-color: true), $lightness: 45%);
22 | color: color.adjust(color('danger', 'alert', $only-color: true), $lightness: -5%);
23 | }
24 |
25 | &__icon {
26 | --size: 0.95em;
27 | block-size: var(--size);
28 | inline-size: var(--size);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Fields/Textarea.php:
--------------------------------------------------------------------------------
1 | class(['form-control']);
24 | }
25 |
26 | /**
27 | * Set the rows attribute.
28 | */
29 | public function rows(int|Closure $value): static
30 | {
31 | return $this->setAttribute('rows', $value);
32 | }
33 |
34 | /**
35 | * Set the cols attribute.
36 | */
37 | public function cols(int|Closure $value): static
38 | {
39 | return $this->setAttribute('cols', $value);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/database/migrations/2020_07_01_000000_create_root_meta_data_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->uuidMorphs('metable');
19 | $table->string('key')->index();
20 | $table->text('value')->nullable();
21 | $table->timestamps();
22 |
23 | $table->unique(['metable_id', 'metable_type', 'key']);
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | */
30 | public function down(): void
31 | {
32 | Schema::dropIfExists('root_meta_data');
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/resources/views/actions/actions.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
10 |
24 |
25 |
--------------------------------------------------------------------------------
/src/Traits/Translatable.php:
--------------------------------------------------------------------------------
1 | morphMany(Translation::getProxiedClass(), 'translatable');
19 | }
20 |
21 | /**
22 | * Translate the value of the given key.
23 | */
24 | public function translate(string $key, ?string $locale = null): mixed
25 | {
26 | $locale ??= App::getLocale();
27 |
28 | return match ($locale) {
29 | (Translation::proxy())::getTranslatableLocale() => $this->getAttribute($key),
30 | default => $this->translations->firstWhere('locale', $locale)?->values[$key] ?? $this->getAttribute($key),
31 | };
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/View/Components/Layout/SidebarGroup.php:
--------------------------------------------------------------------------------
1 | title = $title;
28 | $this->items = $items;
29 | }
30 |
31 | /**
32 | * Get the view / view contents that represent the component.
33 | */
34 | public function render(): View
35 | {
36 | return $this->view('root::components.layout.sidebar-group', [
37 | 'title' => $this->title,
38 | 'items' => $this->items,
39 | ]);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Fields/Checkbox.php:
--------------------------------------------------------------------------------
1 | class('form-check__control')
37 | ->setAttributes([
38 | 'type' => 'checkbox',
39 | 'name' => sprintf('%s[]', $this->getModelAttribute()),
40 | ]);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Settings/Registry.php:
--------------------------------------------------------------------------------
1 | repository = $repository;
23 | }
24 |
25 | /**
26 | * Get the repository instance.
27 | */
28 | public function getRepository(): Repository
29 | {
30 | return $this->repository;
31 | }
32 |
33 | /**
34 | * Dynamically call the given method.
35 | */
36 | public function __call(string $name, array $arguments): mixed
37 | {
38 | return call_user_func_array([$this->repository, $name], $arguments);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/database/migrations/2024_03_21_175513_create_root_events_table.php:
--------------------------------------------------------------------------------
1 | id();
19 | $table->foreignIdFor(User::getProxiedClass())->nullable()->constrained()->nullOnDelete();
20 | $table->uuidMorphs('target');
21 | $table->string('action');
22 | $table->json('payload')->nullable();
23 | $table->timestamps();
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | */
30 | public function down(): void
31 | {
32 | Schema::drop('root_events');
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/resources/views/icons/bazar-emblem.blade.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/database/migrations/2024_11_07_195330_create_root_translations_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->morphs('translatable');
19 | $table->string('locale', 8);
20 | $table->json('values')->nullable();
21 | $table->timestamps();
22 |
23 | $table->unique(['translatable_id', 'translatable_type', 'locale'], 'root_translatable_locale');
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | */
30 | public function down(): void
31 | {
32 | Schema::dropIfExists('root_translations');
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/resources/sass/extend/_progress.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .progressbar {
4 | display: flex;
5 | flex-direction: column;
6 | gap: spacer('xs');
7 | inline-size: 100%;
8 |
9 | &__inner {
10 | background-color: color('background', 'form');
11 | block-size: 0.5rem;
12 | border-radius: config('border-radius-sm', $display);
13 | box-shadow: inset 0 0 0 1px color('border', 'form');
14 | position: relative;
15 | }
16 |
17 | &__indicator {
18 | background-color: color('primary');
19 | block-size: 100%;
20 | border-radius: config('border-radius-sm', $display);
21 | inset: 0 auto 0 0;
22 | position: absolute;
23 |
24 | &:not([style*='inline-size']) {
25 | animation: 1s progress infinite linear alternate;
26 | inline-size: 20%;
27 | }
28 | }
29 |
30 | &__caption {
31 | text-align: center;
32 | }
33 | }
34 |
35 | @keyframes progress {
36 | 0% {
37 | inset-inline-start: 0%;
38 | }
39 |
40 | 100% {
41 | inset-inline-start: 80%;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/resources/sass/extend/_btn.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:color';
2 | @use 'sprucecss/scss/spruce' as *;
3 |
4 | .btn--light {
5 | @include btn-variant('light');
6 |
7 | &.btn--active {
8 | background-color: color('light-background-hover', 'btn');
9 | border-color: color('light-background-hover', 'btn');
10 | color: color('light-foreground-hover', 'btn');
11 | }
12 | }
13 |
14 | .btn--delete {
15 | @include btn-variant('delete');
16 | }
17 |
18 | .btn--dark {
19 | @include btn-variant('dark');
20 | }
21 |
22 | .btn--outline-dark {
23 | @include btn-variant-outline('dark');
24 | }
25 |
26 | .btn {
27 | &--counter {
28 | position: relative;
29 | }
30 |
31 | &__counter {
32 | background-color: color('danger', 'alert');
33 | border-radius: config('border-radius-sm', $display);
34 | color: color('primary-foreground', 'btn');
35 | font-size: 0.6375rem;
36 | inset: -0.5em -0.5em auto auto;
37 | min-inline-size: 1.25rem;
38 | padding: 0.45em;
39 | position: absolute;
40 | text-align: center;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/resources/views/fields/repeater.blade.php:
--------------------------------------------------------------------------------
1 |
20 |
21 | {{-- Script --}}
22 | @pushOnce('scripts')
23 | {{
24 | Vite::withEntryPoints('resources/js/repeater.js')
25 | ->useBuildDirectory('vendor/root/build')
26 | ->useHotFile(public_path('vendor/root/hot'))
27 | }}
28 | @endpushOnce
29 |
--------------------------------------------------------------------------------
/database/factories/MediumFactory.php:
--------------------------------------------------------------------------------
1 |
18 | */
19 | protected $model = Medium::class;
20 |
21 | /**
22 | * Define the model's default state.
23 | */
24 | public function definition(): array
25 | {
26 | return [
27 | 'disk' => 'public',
28 | 'name' => $name = Str::random(5),
29 | 'file_name' => "{$name}.{$this->faker->fileExtension()}",
30 | 'mime_type' => Arr::random(['image/jpg', 'application/pdf']),
31 | 'size' => mt_rand(100, 2000),
32 | 'width' => 1600,
33 | 'height' => 1200,
34 | ];
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Traits/InteractsWithProxy.php:
--------------------------------------------------------------------------------
1 | make(
27 | static::getProxiedInterface()
28 | );
29 | } catch (Throwable) {
30 | $proxy = new static;
31 | }
32 | }
33 |
34 | return $proxy;
35 | }
36 |
37 | /**
38 | * Get the proxied class.
39 | */
40 | public static function getProxiedClass(): string
41 | {
42 | return static::proxy()::class;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/resources/views/resources/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('root::app')
2 |
3 | {{-- Title --}}
4 | @section('title', $title)
5 |
6 | {{-- Actions --}}
7 | @section('actions')
8 | @if(! empty($standaloneActions))
9 |
10 | @include('root::actions.actions', ['actions' => $standaloneActions])
11 |
12 | @endif
13 | @if($abilities['create'])
14 |
15 |
16 | {{ __('Add :resource', ['resource' => $modelName]) }}
17 |
18 | @endif
19 | @endsection
20 |
21 | {{-- Content --}}
22 | @section('content')
23 | @if(! empty($widgets))
24 |
25 | @foreach($widgets as $widget)
26 | @include($widget['template'], $widget)
27 | @endforeach
28 |
29 | @endif
30 |
31 | @include('root::table.table')
32 | @endsection
33 |
--------------------------------------------------------------------------------
/src/Models/Attachment.php:
--------------------------------------------------------------------------------
1 |
15 | */
16 | protected $casts = [
17 | 'meta' => 'json',
18 | ];
19 |
20 | /**
21 | * The attributes that are mass assignable.
22 | *
23 | * @var list
24 | */
25 | protected $fillable = [
26 | 'collection',
27 | 'meta',
28 | ];
29 |
30 | /**
31 | * The table associated with the model.
32 | *
33 | * @var string
34 | */
35 | protected $table = 'root_mediables';
36 |
37 | /**
38 | * Get the attributes that should be cast.
39 | *
40 | * @return array{'meta':'json'}
41 | */
42 | protected function casts(): array
43 | {
44 | return [
45 | 'meta' => 'json',
46 | ];
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Fields/Number.php:
--------------------------------------------------------------------------------
1 | type('number');
19 | }
20 |
21 | /**
22 | * Set the "min" HTML attribute.
23 | */
24 | public function min(int|float|Closure $value): static
25 | {
26 | return $this->setAttribute('min', $value);
27 | }
28 |
29 | /**
30 | * Set the "max" HTML attribute.
31 | */
32 | public function max(int|float|Closure $value): static
33 | {
34 | return $this->setAttribute('max', $value);
35 | }
36 |
37 | /**
38 | * Set the "step" HTML attribute.
39 | */
40 | public function step(int|float|Closure $value): static
41 | {
42 | return $this->setAttribute('step', $value);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/database/factories/AuthCodeFactory.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | protected $model = AuthCode::class;
19 |
20 | /**
21 | * Define the model's default state.
22 | */
23 | public function definition(): array
24 | {
25 | return [
26 | 'code' => mt_rand(100000, 999999),
27 | 'expires_at' => Date::now()->addMinutes(5),
28 | ];
29 | }
30 |
31 | /**
32 | * Indicate that the model should be expired.
33 | */
34 | public function expired(): static
35 | {
36 | return $this->state(fn (array $attributes) => [
37 | 'expires_at' => Date::now()->subMinute(),
38 | ]);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/database/migrations/2023_08_15_101934_create_root_notifications_table.php:
--------------------------------------------------------------------------------
1 | uuid('id')->primary();
18 | $table->string('type');
19 | $table->morphs('notifiable');
20 | $table->string('subject')->index();
21 | $table->text('message')->nullable();
22 | $table->json('data')->nullable();
23 | $table->timestamp('read_at')->nullable();
24 | $table->timestamps();
25 | });
26 | }
27 |
28 | /**
29 | * Reverse the migrations.
30 | */
31 | public function down(): void
32 | {
33 | Schema::dropIfExists('root_notifications');
34 | }
35 | };
36 |
--------------------------------------------------------------------------------
/src/Fields/Text.php:
--------------------------------------------------------------------------------
1 | type('text');
19 | }
20 |
21 | /**
22 | * Set the "size" HTML attribute.
23 | */
24 | public function size(int|Closure $value): static
25 | {
26 | return $this->setAttribute('size', $value);
27 | }
28 |
29 | /**
30 | * Set the "minlength" HTML attribute.
31 | */
32 | public function minlength(int|Closure $value): static
33 | {
34 | return $this->setAttribute('minlength', $value);
35 | }
36 |
37 | /**
38 | * Set the "maxlength" HTML attribute.
39 | */
40 | public function maxlength(int|Closure $value): static
41 | {
42 | return $this->setAttribute('maxlength', $value);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/stubs/RootServiceProvider.stub:
--------------------------------------------------------------------------------
1 | User::class,
19 | ];
20 |
21 | /**
22 | * Register any application services.
23 | */
24 | public function register(): void
25 | {
26 | //
27 | }
28 |
29 | /**
30 | * Bootstrap any application services.
31 | */
32 | public function boot(): void
33 | {
34 | Gate::define('viewRoot', static function (User $user): bool {
35 | return false;
36 | });
37 |
38 | Root::instance()->widgets->register([
39 | new Welcome,
40 | ]);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/resources/views/icons/spruce-emblem.blade.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/Traits/HasMedia.php:
--------------------------------------------------------------------------------
1 | forceDeleting || ! in_array(SoftDeletes::class, class_uses_recursive($model))) {
21 | $model->media()->detach();
22 | }
23 | });
24 | }
25 |
26 | /**
27 | * Get the media for the model.
28 | */
29 | public function media(): MorphToMany
30 | {
31 | return $this->morphToMany(Medium::getProxiedClass(), 'mediable', 'root_mediables')
32 | ->as('attachment')
33 | ->using(Attachment::class)
34 | ->withPivot(['meta', 'collection'])
35 | ->withTimestamps();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/resources/views/actions/action.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @if(! empty($fields))
3 |
4 | @foreach($fields as $field)
5 | @include($field['template'], $field)
6 | @endforeach
7 |
8 | @endif
9 |
10 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/resources/js/helpers.js:
--------------------------------------------------------------------------------
1 | const debounce = (callback, delay = 300) => {
2 | let timeoutID = null;
3 |
4 | return function () {
5 | clearTimeout(timeoutID);
6 |
7 | const args = arguments;
8 | const context = this;
9 |
10 | timeoutID = setTimeout(function () {
11 | callback.apply(context, args);
12 | }, delay);
13 | };
14 | };
15 |
16 | const throttle = (callback, wait = 300) => {
17 | let timeoutID, lastTick;
18 |
19 | return function () {
20 | const args = arguments;
21 | const context = this;
22 |
23 | if (! lastTick) {
24 | callback.apply(context, args);
25 | lastTick = Date.now();
26 | } else {
27 | clearTimeout(timeoutID);
28 | timeoutID = setTimeout(function () {
29 | if ((Date.now() - lastTick) >= wait) {
30 | callback.apply(context, args);
31 | lastTick = Date.now();
32 | }
33 | }, wait - (Date.now() - lastTick));
34 | }
35 | };
36 | };
37 |
38 | export { debounce, throttle };
39 |
--------------------------------------------------------------------------------
/resources/views/icons/format-ordered-list.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Cone Development
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/resources/views/icons/format-unlink.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/Casts/MetaValue.php:
--------------------------------------------------------------------------------
1 | $attributes
17 | */
18 | public function get(Model $model, string $key, mixed $value, array $attributes): mixed
19 | {
20 | return is_null($value) ? $value : (json_decode($value, true) ?? $value);
21 | }
22 |
23 | /**
24 | * Prepare the given value for storage.
25 | *
26 | * @param array $attributes
27 | */
28 | public function set(Model $model, string $key, mixed $value, array $attributes): string|false|null
29 | {
30 | return match (true) {
31 | is_null($value) => null,
32 | is_string($value), is_numeric($value), $value instanceof Stringable => (string) $value,
33 | default => json_encode($value) ?: (string) $value,
34 | };
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/resources/sass/component/_welcome-card.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .welcome-card {
4 | @include a11y-card-link('.welcome-card__link', true);
5 | $this: &;
6 | display: flex;
7 | gap: spacer('m');
8 | padding: spacer-clamp('m', 2rem);
9 |
10 | &__icon {
11 | --size: 3rem;
12 | align-items: center;
13 | background-color: color('icon-background', 'widget');
14 | block-size: var(--size);
15 | border-radius: config('border-radius-sm', $display);
16 | color: color('primary');
17 | display: flex;
18 | flex-shrink: 0;
19 | inline-size: var(--size);
20 | justify-content: center;
21 |
22 | svg {
23 | --size: 1.4rem;
24 | block-size: var(--size);
25 | inline-size: var(--size);
26 | }
27 | }
28 |
29 | &__title {
30 | font-size: font-size('h4');
31 | font-weight: 600;
32 | margin-block: 0;
33 | }
34 |
35 | &__link {
36 | color: color('heading');
37 | text-decoration: none;
38 |
39 | &:hover,
40 | &:focus {
41 | color: color('heading');
42 | }
43 | }
44 |
45 | &__body {
46 | @include layout-stack('xs');
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/resources/views/fields/slug.blade.php:
--------------------------------------------------------------------------------
1 |
27 |
--------------------------------------------------------------------------------
/src/Interfaces/Models/User.php:
--------------------------------------------------------------------------------
1 | li {
12 | align-items: center;
13 | display: inline-flex;
14 | margin-block: 0;
15 |
16 | + li::before {
17 | block-size: 0.4em;
18 | border-block-end: 2px solid color('separator', 'breadcrumb');
19 | border-inline-end: 2px solid color('separator', 'breadcrumb');
20 | content: '';
21 | display: inline-flex;
22 | inline-size: 0.4em;
23 | margin-inline: 0.75em;
24 | transform: rotate(-45deg);
25 |
26 | @at-root {
27 | /* stylelint-disable-next-line selector-max-compound-selectors */
28 | [dir='rtl'] & {
29 | transform: rotate(45deg);
30 | }
31 | }
32 | }
33 | }
34 |
35 | a {
36 | text-decoration: none;
37 | }
38 |
39 | [aria-current='page'] {
40 | @include text-ellipsis(1);
41 | display: inline-block;
42 | max-inline-size: 20ch;
43 | text-align: start;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Console/Commands/ActionMake.php:
--------------------------------------------------------------------------------
1 | type = $type;
28 | $this->closable = $closable;
29 | }
30 |
31 | /**
32 | * Get the view / view contents that represent the component.
33 | */
34 | public function render(): View
35 | {
36 | return $this->view('root::components.alert', [
37 | 'type' => $this->type,
38 | 'closable' => $this->closable,
39 | 'class' => match ($this->type) {
40 | 'error' => 'alert--danger',
41 | default => 'alert--'.$this->type,
42 | },
43 | ]);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/resources/views/fields/editor/heading.blade.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/resources/views/icons/cone-emblem.blade.php:
--------------------------------------------------------------------------------
1 |
23 |
--------------------------------------------------------------------------------
/resources/views/auth/forgot-password.blade.php:
--------------------------------------------------------------------------------
1 | @extends('root::auth.layout')
2 |
3 | {{-- Title --}}
4 | @section('title', __('Forgot Password'))
5 |
6 | {{-- Content --}}
7 | @section('content')
8 |
32 | @endsection
33 |
--------------------------------------------------------------------------------
/resources/views/components/layout/sidebar-group.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ $title }}
4 |
13 |
14 |
28 |
29 |
--------------------------------------------------------------------------------
/database/factories/NotificationFactory.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | protected $model = Notification::class;
19 |
20 | /**
21 | * Define the model's default state.
22 | */
23 | public function definition(): array
24 | {
25 | return [
26 | 'type' => 'App\\Notifications\\CustomNotification',
27 | 'subject' => $this->faker->jobTitle(),
28 | 'message' => $this->faker->paragraph(),
29 | 'data' => [],
30 | 'read_at' => Date::now(),
31 | ];
32 | }
33 |
34 | /**
35 | * Indicate that the model should be unread.
36 | */
37 | public function unread(): static
38 | {
39 | return $this->state(fn (array $attributes): array => [
40 | 'read_at' => null,
41 | ]);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Traits/ResolvesWidgets.php:
--------------------------------------------------------------------------------
1 | widgets)) {
32 | $this->widgets = new Widgets($this->widgets($request));
33 |
34 | $this->widgets->each(function (Widget $widget) use ($request): void {
35 | $this->resolveWidget($request, $widget);
36 | });
37 | }
38 |
39 | return $this->widgets;
40 | }
41 |
42 | /**
43 | * Handle the callback for the widget resolution.
44 | */
45 | protected function resolveWidget(Request $request, Widget $widget): void
46 | {
47 | //
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/resources/sass/section/_sidebar.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .app-sidebar {
4 | block-size: 100%;
5 | border-inline-end: 1px solid color('border');
6 | display: flex;
7 | flex-direction: column;
8 | gap: spacer('m');
9 | padding-block: 0 spacer('m');
10 |
11 | &__logo {
12 | block-size: 1.25rem;
13 | display: inline-flex;
14 | }
15 |
16 | &__search {
17 | display: none;
18 |
19 | @include breakpoint('md') {
20 | display: flex;
21 | }
22 | }
23 |
24 | &__header {
25 | align-items: center;
26 | block-size: get-css-variable(--header-block-size);
27 | border-block-end: 1px solid color('border');
28 | display: flex;
29 | flex-shrink: 0;
30 | justify-content: space-between;
31 | margin-inline: spacer('m');
32 | }
33 |
34 | &__body {
35 | @include scrollbar(
36 | $border-radius: 0.15em
37 | );
38 | flex-grow: 1;
39 | margin-inline: calc(#{spacer('m')} / 2);
40 | overflow-y: auto;
41 | padding-inline: calc(#{spacer('m')} / 2);
42 |
43 | > * + * {
44 | border-block-start: 1px solid color('border');
45 | margin-block-start: spacer('s');
46 | padding-block-start: spacer('s');
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Jobs/PerformConversions.php:
--------------------------------------------------------------------------------
1 | medium->convert();
43 | }
44 |
45 | /**
46 | * Handle a job failure.
47 | */
48 | public function failed(Throwable $exception): void
49 | {
50 | $this->medium->delete();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/resources/views/fields/date.blade.php:
--------------------------------------------------------------------------------
1 |
31 |
--------------------------------------------------------------------------------
/resources/views/widgets/trend.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
--------------------------------------------------------------------------------
/src/Support/Facades/Conversion.php:
--------------------------------------------------------------------------------
1 | registerConversion($name, $callback);
32 | }
33 |
34 | /**
35 | * Remove the given conversion.
36 | */
37 | public static function remove(string $name): void
38 | {
39 | static::getFacadeRoot()->removeConversion($name);
40 | }
41 |
42 | /**
43 | * Get all the registered conversions.
44 | */
45 | public static function all(): array
46 | {
47 | return static::getFacadeRoot()->getConversions();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/resources/views/media/medium.blade.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/Conversion/GdDriver.php:
--------------------------------------------------------------------------------
1 | createImage($medium);
30 |
31 | call_user_func_array($callback, [$image, $medium]);
32 |
33 | $image->save();
34 |
35 | File::move($image->getPath(), $medium->getAbsolutePath($conversion));
36 |
37 | $image->destroy();
38 | }
39 |
40 | /**
41 | * Create a new image instance.
42 | */
43 | protected function createImage(Medium $medium): Image
44 | {
45 | return tap(new Image($medium), function (Image $image): void {
46 | $image->setQuality($this->config['quality'] ?? 70);
47 | });
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/resources/views/icons/format-bullet-list.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/resources/sass/section/_header.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .app-header {
4 | backdrop-filter: saturate(180%) blur(0.25rem);
5 | background-color: color('background', 'header');
6 | border-block-end: 1px solid color('border');
7 | inset-block-start: 0;
8 | inset-block-start: 0;
9 | position: sticky;
10 | position: sticky;
11 | z-index: 15;
12 |
13 | &__inner {
14 | align-items: center;
15 | block-size: get-css-variable(--header-block-size);
16 | display: flex;
17 | flex-wrap: wrap;
18 | gap: spacer-clamp('s', 'l');
19 | justify-content: space-between;
20 | margin-inline: get-css-variable(--container-gap);
21 | }
22 |
23 | &__column {
24 | align-items: center;
25 | display: flex;
26 | flex-grow: 1;
27 | gap: spacer-clamp('s', 'm');
28 | }
29 |
30 | &__actions {
31 | align-items: center;
32 | display: flex;
33 | gap: spacer-clamp('s', 'm');
34 |
35 | &--secondary {
36 | gap: spacer('s');
37 | }
38 | }
39 |
40 | &__logo {
41 | block-size: 1.25rem;
42 | display: inline-flex;
43 |
44 | @include breakpoint('md') {
45 | display: none;
46 | }
47 | }
48 |
49 | &__breadcrumb {
50 | display: none;
51 |
52 | @include breakpoint('md') {
53 | display: flex;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/resources/views/widgets/value.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | @if(! is_null($icon))
4 |
5 |
6 |
7 | @endif
8 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/resources/sass/component/form/_repeater.scss:
--------------------------------------------------------------------------------
1 | @use 'sprucecss/scss/spruce' as *;
2 |
3 | .repeater-container {
4 | @include layout-stack('s');
5 | }
6 |
7 | .repeater {
8 | @include generate-variables($form-control, $include: ('border-width', 'border-radius'));
9 | border: config('border-width', $form-control) solid color('border', 'form');
10 | border-radius: config('border-radius', $form-control);
11 | padding: spacer('s');
12 |
13 | &__heading {
14 | align-items: center;
15 | display: flex;
16 | flex-wrap: wrap;
17 | gap: spacer('s');
18 | justify-content: space-between;
19 | }
20 |
21 | &__body {
22 | border-block-start: 1px solid color('border');
23 | margin-block-start: spacer('s');
24 | padding-block-start: spacer('s');
25 | }
26 |
27 | &__column {
28 | align-items: center;
29 | display: flex;
30 | gap: spacer('s');
31 | }
32 |
33 | &__title {
34 | @include text-ellipsis(1);
35 | font-size: config('font-size-base', $typography);
36 | margin-block: 0;
37 | max-inline-size: 20ch;
38 | }
39 |
40 | &__actions {
41 | align-items: center;
42 | display: flex;
43 | gap: spacer('xxs');
44 | }
45 |
46 | &__toggle {
47 | &[aria-expanded='true'] {
48 | .vertical-line {
49 | display: none;
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/resources/views/table/actions.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ $data->total() }}
5 |
6 |
7 |
8 |
9 | {{ __('items selected.') }}
10 |
11 |
12 |
13 |
20 |
27 |
28 |
29 | @include('root::actions.actions', ['class' => 'btn--sm'])
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/routes/auth.php:
--------------------------------------------------------------------------------
1 | name('login');
13 | Route::post('/login', [LoginController::class, 'login']);
14 | Route::post('/logout', [LoginController::class, 'logout'])->name('logout');
15 |
16 | // Reset
17 | Route::get('/password/reset', [ForgotPasswordController::class, 'show'])->name('password.request');
18 | Route::post('/password/email', [ForgotPasswordController::class, 'send'])->name('password.email');
19 | Route::get('/password/reset/{token}/{email}', [ResetPasswordController::class, 'show'])->name('password.reset');
20 | Route::post('/password/reset', [ResetPasswordController::class, 'reset'])->name('password.update');
21 |
22 | // Two Factor Verification
23 | Route::get('/two-factor', [TwoFactorController::class, 'show'])->name('two-factor.show');
24 | Route::post('/two-factor', [TwoFactorController::class, 'verify'])->name('two-factor.verify');
25 | Route::post('/two-factor/resend', [TwoFactorController::class, 'resend'])->name('two-factor.resend');
26 |
--------------------------------------------------------------------------------
/src/Console/Commands/ClearMedia.php:
--------------------------------------------------------------------------------
1 | option('all');
35 |
36 | Medium::proxy()
37 | ->newQuery()
38 | ->cursor()
39 | ->each(static function (Medium $medium) use (&$count, $all): void {
40 | if ($all || ! Storage::disk($medium->disk)->exists($medium->getPath())) {
41 | $medium->delete();
42 |
43 | $count++;
44 | }
45 | });
46 |
47 | $this->info(sprintf('%d media have been deleted!', $count));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/resources/views/table/column.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @if($sortable)
3 | @if(Request::input($sortKey.'.by') !== $attribute || Request::input($sortKey.'.order', 'asc') === 'asc')
4 |
10 | {{ $label }}
11 | @if(Request::input($sortKey.'.by') !== $attribute)
12 |
13 | @else
14 |
15 | @endif
16 |
17 | @else
18 |
24 | {{ $label }}
25 |
26 |
27 | @endif
28 | @else
29 | {{ $label }}
30 | @endif
31 | |
32 |
--------------------------------------------------------------------------------
/src/Filters/TrashStatus.php:
--------------------------------------------------------------------------------
1 | getModel()))) {
19 | return $query;
20 | }
21 |
22 | return match ($value) {
23 | 'all' => $query->withTrashed(),
24 | 'trashed' => $query->onlyTrashed(),
25 | default => $query,
26 | };
27 | }
28 |
29 | /**
30 | * Determine if the filter is active.
31 | */
32 | public function isActive(Request $request): bool
33 | {
34 | return parent::isActive($request)
35 | && $this->getValue($request) !== 'available';
36 | }
37 |
38 | /**
39 | * Get the filter options.
40 | */
41 | public function options(Request $request): array
42 | {
43 | return [
44 | 'available' => __('Available'),
45 | 'trashed' => __('Trashed'),
46 | 'all' => __('All'),
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Console/Commands/Install.php:
--------------------------------------------------------------------------------
1 | call('migrate');
35 |
36 | File::ensureDirectoryExists(Config::get('root.media.tmp_dir'));
37 |
38 | if ($this->option('seed')) {
39 | $this->call('db:seed', ['--class' => RootTestDataSeeder::class]);
40 | }
41 |
42 | $this->call('vendor:publish', [
43 | '--provider' => RootServiceProvider::class,
44 | '--tag' => 'root-stubs',
45 | ]);
46 |
47 | $this->info('Root has been installed.');
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Http/Controllers/MediaController.php:
--------------------------------------------------------------------------------
1 | route('_resource');
20 |
21 | /** @var \Cone\Root\Fields\Media $field */
22 | $field = $request->route('field');
23 |
24 | $model = $request->filled('model')
25 | ? $resource->resolveRouteBinding($request, $request->input('model'))
26 | : $resource->getModelInstance();
27 |
28 | return match ($request->method()) {
29 | 'GET' => new JsonResponse($field->paginateRelatable($request, $model)),
30 | 'POST' => new JsonResponse($field->upload($request, $model), JsonResponse::HTTP_CREATED),
31 | 'DELETE' => new JsonResponse(['deleted' => $field->prune($request, $model, $request->input('ids', []))]),
32 | default => throw new MethodNotAllowedHttpException(['GET', 'POST', 'DELETE']),
33 | };
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Support/Copyable.php:
--------------------------------------------------------------------------------
1 | ', $this->text, $this->value));
36 | }
37 |
38 | /**
39 | * Get content as a string of HTML.
40 | */
41 | public function toHtml(): string
42 | {
43 | return $this->render();
44 | }
45 |
46 | /**
47 | * Get the string representation of the object.
48 | */
49 | public function __toString(): string
50 | {
51 | return $this->toHtml();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/resources/views/components/layout/theme.blade.php:
--------------------------------------------------------------------------------
1 |
7 |
15 |
23 |
31 |
32 |
33 | {{-- Scripts --}}
34 | @pushOnce('scripts')
35 | {{
36 | Vite::withEntryPoints('resources/js/theme.js')
37 | ->useBuildDirectory('vendor/root/build')
38 | ->useHotFile(public_path('vendor/root/hot'))
39 | }}
40 | @endPushOnce
41 |
--------------------------------------------------------------------------------
/src/Console/Commands/ClearChunks.php:
--------------------------------------------------------------------------------
1 | allFiles(Config::get('root.media.upload_dir')) as $file) {
40 | $info = new SplFileInfo(Storage::disk('local')->path($file));
41 |
42 | if ($now - $info->getMTime() >= $expiration) {
43 | Storage::disk('local')->delete($file);
44 |
45 | $count++;
46 | }
47 | }
48 |
49 | $this->info(sprintf('%d chunks are cleared!', $count));
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/resources/views/resources/relation.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 | @include('root::table.body')
18 |
19 |
20 | {{-- Script --}}
21 |
24 | @pushOnce('scripts')
25 | {{
26 | Vite::withEntryPoints('resources/js/table.js')
27 | ->useBuildDirectory('vendor/root/build')
28 | ->useHotFile(public_path('vendor/root/hot'))
29 | }}
30 | @endpushOnce
31 |
32 |
--------------------------------------------------------------------------------
/src/View/Components/Modal.php:
--------------------------------------------------------------------------------
1 | title = $title;
39 | $this->subtitle = $subtitle;
40 | $this->key = strtolower($key ?: Str::random());
41 | $this->open = $open;
42 | }
43 |
44 | /**
45 | * Get the view / view contents that represent the component.
46 | */
47 | public function render(): View
48 | {
49 | return $this->view('root::components.modal', [
50 | 'key' => $this->key,
51 | 'subtitle' => $this->subtitle,
52 | 'title' => $this->title,
53 | 'open' => $this->open,
54 | ]);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Traits/AsForm.php:
--------------------------------------------------------------------------------
1 | validateWithBag(
38 | $this->errorBag,
39 | $this->resolveFields($request)->mapToValidate($request, $model)
40 | );
41 | }
42 |
43 | /**
44 | * Get the errors.
45 | */
46 | public function errors(Request $request): MessageBag
47 | {
48 | if (is_null($this->errors)) {
49 | $this->errors = $request->session()->get('errors', new ViewErrorBag)->getBag($this->errorBag);
50 | }
51 |
52 | return $this->errors;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/resources/views/fields/editor/link.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
11 |
20 |
21 |
22 | {{-- Script --}}
23 | @pushOnce('scripts')
24 |
38 | @endpushOnce
39 |
--------------------------------------------------------------------------------