[增添]添加了datasource的setting数据库以及默认值
This commit is contained in:
96
vendor/filament/widgets/resources/js/components/chart.js
vendored
Normal file
96
vendor/filament/widgets/resources/js/components/chart.js
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
import Chart from 'chart.js/auto'
|
||||
import 'chartjs-adapter-luxon'
|
||||
|
||||
export default function chart({ cachedData, options, type }) {
|
||||
return {
|
||||
init: function () {
|
||||
this.initChart()
|
||||
|
||||
this.$wire.$on('updateChartData', ({ data }) => {
|
||||
chart = this.getChart()
|
||||
chart.data = data
|
||||
chart.update('resize')
|
||||
})
|
||||
|
||||
Alpine.effect(() => {
|
||||
Alpine.store('theme')
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (!this.getChart()) {
|
||||
return
|
||||
}
|
||||
|
||||
this.getChart().destroy()
|
||||
this.initChart()
|
||||
})
|
||||
})
|
||||
|
||||
window
|
||||
.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', () => {
|
||||
if (Alpine.store('theme') !== 'system') {
|
||||
return
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getChart().destroy()
|
||||
this.initChart()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
initChart: function (data = null) {
|
||||
Chart.defaults.animation.duration = 0
|
||||
|
||||
Chart.defaults.backgroundColor = getComputedStyle(
|
||||
this.$refs.backgroundColorElement,
|
||||
).color
|
||||
|
||||
const borderColor = getComputedStyle(
|
||||
this.$refs.borderColorElement,
|
||||
).color
|
||||
|
||||
Chart.defaults.borderColor = borderColor
|
||||
|
||||
Chart.defaults.color = getComputedStyle(
|
||||
this.$refs.textColorElement,
|
||||
).color
|
||||
|
||||
Chart.defaults.font.family = getComputedStyle(this.$el).fontFamily
|
||||
|
||||
Chart.defaults.plugins.legend.labels.boxWidth = 12
|
||||
Chart.defaults.plugins.legend.position = 'bottom'
|
||||
|
||||
const gridColor = getComputedStyle(
|
||||
this.$refs.gridColorElement,
|
||||
).color
|
||||
|
||||
options ??= {}
|
||||
options.borderWidth ??= 2
|
||||
options.pointBackgroundColor ??= borderColor
|
||||
options.pointHitRadius ??= 4
|
||||
options.pointRadius ??= 2
|
||||
options.scales ??= {}
|
||||
options.scales.x ??= {}
|
||||
options.scales.x.grid ??= {}
|
||||
options.scales.x.grid.color = gridColor
|
||||
options.scales.x.grid.display ??= false
|
||||
options.scales.x.grid.drawBorder ??= false
|
||||
options.scales.y ??= {}
|
||||
options.scales.y.grid ??= {}
|
||||
options.scales.y.grid.color = gridColor
|
||||
options.scales.y.grid.drawBorder ??= false
|
||||
|
||||
return new Chart(this.$refs.canvas, {
|
||||
type: type,
|
||||
data: data ?? cachedData,
|
||||
options: options,
|
||||
plugins: window.filamentChartJsPlugins ?? [],
|
||||
})
|
||||
},
|
||||
|
||||
getChart: function () {
|
||||
return Chart.getChart(this.$refs.canvas)
|
||||
},
|
||||
}
|
||||
}
|
||||
99
vendor/filament/widgets/resources/js/components/stats-overview/stat/chart.js
vendored
Normal file
99
vendor/filament/widgets/resources/js/components/stats-overview/stat/chart.js
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
import Chart from 'chart.js/auto'
|
||||
|
||||
export default function statsOverviewStatChart({
|
||||
dataChecksum,
|
||||
labels,
|
||||
values,
|
||||
}) {
|
||||
return {
|
||||
dataChecksum,
|
||||
|
||||
init: function () {
|
||||
Alpine.effect(() => {
|
||||
Alpine.store('theme')
|
||||
|
||||
const chart = this.getChart()
|
||||
|
||||
if (chart) {
|
||||
chart.destroy()
|
||||
}
|
||||
|
||||
this.initChart()
|
||||
})
|
||||
|
||||
window
|
||||
.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', () => {
|
||||
if (Alpine.store('theme') !== 'system') {
|
||||
return
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
const chart = this.getChart()
|
||||
|
||||
if (chart) {
|
||||
chart.destroy()
|
||||
}
|
||||
|
||||
this.initChart()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
initChart: function () {
|
||||
Chart.defaults.backgroundColor = getComputedStyle(
|
||||
this.$refs.backgroundColorElement,
|
||||
).color
|
||||
|
||||
Chart.defaults.borderColor = getComputedStyle(
|
||||
this.$refs.borderColorElement,
|
||||
).color
|
||||
|
||||
return new Chart(this.$refs.canvas, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
data: values,
|
||||
borderWidth: 2,
|
||||
fill: 'start',
|
||||
tension: 0.5,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
animation: {
|
||||
duration: 0,
|
||||
},
|
||||
elements: {
|
||||
point: {
|
||||
radius: 0,
|
||||
},
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
display: false,
|
||||
},
|
||||
y: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
tooltips: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
getChart: function () {
|
||||
return Chart.getChart(this.$refs.canvas)
|
||||
},
|
||||
}
|
||||
}
|
||||
113
vendor/filament/widgets/resources/views/chart-widget.blade.php
vendored
Normal file
113
vendor/filament/widgets/resources/views/chart-widget.blade.php
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
@php
|
||||
use Filament\Support\Facades\FilamentView;
|
||||
|
||||
$color = $this->getColor();
|
||||
$heading = $this->getHeading();
|
||||
$description = $this->getDescription();
|
||||
$filters = $this->getFilters();
|
||||
@endphp
|
||||
|
||||
<x-filament-widgets::widget class="fi-wi-chart">
|
||||
<x-filament::section :description="$description" :heading="$heading">
|
||||
@if ($filters)
|
||||
<x-slot name="headerEnd">
|
||||
<x-filament::input.wrapper
|
||||
inline-prefix
|
||||
wire:target="filter"
|
||||
class="w-max sm:-my-2"
|
||||
>
|
||||
<x-filament::input.select
|
||||
inline-prefix
|
||||
wire:model.live="filter"
|
||||
>
|
||||
@foreach ($filters as $value => $label)
|
||||
<option value="{{ $value }}">
|
||||
{{ $label }}
|
||||
</option>
|
||||
@endforeach
|
||||
</x-filament::input.select>
|
||||
</x-filament::input.wrapper>
|
||||
</x-slot>
|
||||
@endif
|
||||
|
||||
<div
|
||||
@if ($pollingInterval = $this->getPollingInterval())
|
||||
wire:poll.{{ $pollingInterval }}="updateChartData"
|
||||
@endif
|
||||
>
|
||||
<div
|
||||
@if (FilamentView::hasSpaMode())
|
||||
ax-load="visible"
|
||||
@else
|
||||
ax-load
|
||||
@endif
|
||||
ax-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('chart', 'filament/widgets') }}"
|
||||
wire:ignore
|
||||
x-data="chart({
|
||||
cachedData: @js($this->getCachedData()),
|
||||
options: @js($this->getOptions()),
|
||||
type: @js($this->getType()),
|
||||
})"
|
||||
x-ignore
|
||||
@class([
|
||||
match ($color) {
|
||||
'gray' => null,
|
||||
default => 'fi-color-custom',
|
||||
},
|
||||
is_string($color) ? "fi-color-{$color}" : null,
|
||||
])
|
||||
>
|
||||
<canvas
|
||||
x-ref="canvas"
|
||||
@if ($maxHeight = $this->getMaxHeight())
|
||||
style="max-height: {{ $maxHeight }}"
|
||||
@endif
|
||||
></canvas>
|
||||
|
||||
<span
|
||||
x-ref="backgroundColorElement"
|
||||
@class([
|
||||
match ($color) {
|
||||
'gray' => 'text-gray-100 dark:text-gray-800',
|
||||
default => 'text-custom-50 dark:text-custom-400/10',
|
||||
},
|
||||
])
|
||||
@style([
|
||||
\Filament\Support\get_color_css_variables(
|
||||
$color,
|
||||
shades: [50, 400],
|
||||
alias: 'widgets::chart-widget.background',
|
||||
) => $color !== 'gray',
|
||||
])
|
||||
></span>
|
||||
|
||||
<span
|
||||
x-ref="borderColorElement"
|
||||
@class([
|
||||
match ($color) {
|
||||
'gray' => 'text-gray-400',
|
||||
default => 'text-custom-500 dark:text-custom-400',
|
||||
},
|
||||
])
|
||||
@style([
|
||||
\Filament\Support\get_color_css_variables(
|
||||
$color,
|
||||
shades: [400, 500],
|
||||
alias: 'widgets::chart-widget.border',
|
||||
) => $color !== 'gray',
|
||||
])
|
||||
></span>
|
||||
|
||||
<span
|
||||
x-ref="gridColorElement"
|
||||
class="text-gray-200 dark:text-gray-800"
|
||||
></span>
|
||||
|
||||
<span
|
||||
x-ref="textColorElement"
|
||||
class="text-gray-500 dark:text-gray-400"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
</x-filament::section>
|
||||
</x-filament-widgets::widget>
|
||||
35
vendor/filament/widgets/resources/views/components/widget.blade.php
vendored
Normal file
35
vendor/filament/widgets/resources/views/components/widget.blade.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
@php
|
||||
$columnSpan = $this->getColumnSpan();
|
||||
|
||||
if (! is_array($columnSpan)) {
|
||||
$columnSpan = [
|
||||
'default' => $columnSpan,
|
||||
];
|
||||
}
|
||||
|
||||
$columnStart = $this->getColumnStart();
|
||||
|
||||
if (! is_array($columnStart)) {
|
||||
$columnStart = [
|
||||
'default' => $columnStart,
|
||||
];
|
||||
}
|
||||
@endphp
|
||||
|
||||
<x-filament::grid.column
|
||||
:default="$columnSpan['default'] ?? 1"
|
||||
:sm="$columnSpan['sm'] ?? null"
|
||||
:md="$columnSpan['md'] ?? null"
|
||||
:lg="$columnSpan['lg'] ?? null"
|
||||
:xl="$columnSpan['xl'] ?? null"
|
||||
:twoXl="$columnSpan['2xl'] ?? null"
|
||||
:defaultStart="$columnStart['default'] ?? null"
|
||||
:smStart="$columnStart['sm'] ?? null"
|
||||
:mdStart="$columnStart['md'] ?? null"
|
||||
:lgStart="$columnStart['lg'] ?? null"
|
||||
:xlStart="$columnStart['xl'] ?? null"
|
||||
:twoXlStart="$columnStart['2xl'] ?? null"
|
||||
:attributes="\Filament\Support\prepare_inherited_attributes($attributes)->class('fi-wi-widget')"
|
||||
>
|
||||
{{ $slot }}
|
||||
</x-filament::grid.column>
|
||||
39
vendor/filament/widgets/resources/views/components/widgets.blade.php
vendored
Normal file
39
vendor/filament/widgets/resources/views/components/widgets.blade.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
@props([
|
||||
'columns' => [
|
||||
'lg' => 2,
|
||||
],
|
||||
'data' => [],
|
||||
'widgets' => [],
|
||||
])
|
||||
|
||||
<x-filament::grid
|
||||
:default="$columns['default'] ?? 1"
|
||||
:sm="$columns['sm'] ?? null"
|
||||
:md="$columns['md'] ?? null"
|
||||
:lg="$columns['lg'] ?? ($columns ? (is_array($columns) ? null : $columns) : 2)"
|
||||
:xl="$columns['xl'] ?? null"
|
||||
:two-xl="$columns['2xl'] ?? null"
|
||||
:attributes="\Filament\Support\prepare_inherited_attributes($attributes)->class('fi-wi gap-6')"
|
||||
>
|
||||
@php
|
||||
$normalizeWidgetClass = function (string | Filament\Widgets\WidgetConfiguration $widget): string {
|
||||
if ($widget instanceof \Filament\Widgets\WidgetConfiguration) {
|
||||
return $widget->widget;
|
||||
}
|
||||
|
||||
return $widget;
|
||||
};
|
||||
@endphp
|
||||
|
||||
@foreach ($widgets as $widgetKey => $widget)
|
||||
@php
|
||||
$widgetClass = $normalizeWidgetClass($widget);
|
||||
@endphp
|
||||
|
||||
@livewire(
|
||||
$widgetClass,
|
||||
[...(($widget instanceof \Filament\Widgets\WidgetConfiguration) ? [...$widget->widget::getDefaultProperties(), ...$widget->getProperties()] : $widget::getDefaultProperties()), ...$data],
|
||||
key("{$widgetClass}-{$widgetKey}"),
|
||||
)
|
||||
@endforeach
|
||||
</x-filament::grid>
|
||||
22
vendor/filament/widgets/resources/views/stats-overview-widget.blade.php
vendored
Normal file
22
vendor/filament/widgets/resources/views/stats-overview-widget.blade.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
@php
|
||||
$columns = $this->getColumns();
|
||||
@endphp
|
||||
|
||||
<x-filament-widgets::widget class="fi-wi-stats-overview">
|
||||
<div
|
||||
@if ($pollingInterval = $this->getPollingInterval())
|
||||
wire:poll.{{ $pollingInterval }}
|
||||
@endif
|
||||
@class([
|
||||
'fi-wi-stats-overview-stats-ctn grid gap-6',
|
||||
'md:grid-cols-1' => $columns === 1,
|
||||
'md:grid-cols-2' => $columns === 2,
|
||||
'md:grid-cols-3' => $columns === 3,
|
||||
'md:grid-cols-2 xl:grid-cols-4' => $columns === 4,
|
||||
])
|
||||
>
|
||||
@foreach ($this->getCachedStats() as $stat)
|
||||
{{ $stat }}
|
||||
@endforeach
|
||||
</div>
|
||||
</x-filament-widgets::widget>
|
||||
159
vendor/filament/widgets/resources/views/stats-overview-widget/stat.blade.php
vendored
Normal file
159
vendor/filament/widgets/resources/views/stats-overview-widget/stat.blade.php
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
@php
|
||||
use Filament\Support\Enums\IconPosition;
|
||||
use Filament\Support\Facades\FilamentView;
|
||||
|
||||
$chartColor = $getChartColor() ?? 'gray';
|
||||
$descriptionColor = $getDescriptionColor() ?? 'gray';
|
||||
$descriptionIcon = $getDescriptionIcon();
|
||||
$descriptionIconPosition = $getDescriptionIconPosition();
|
||||
$url = $getUrl();
|
||||
$tag = $url ? 'a' : 'div';
|
||||
$dataChecksum = $generateDataChecksum();
|
||||
|
||||
$descriptionIconClasses = \Illuminate\Support\Arr::toCssClasses([
|
||||
'fi-wi-stats-overview-stat-description-icon h-5 w-5',
|
||||
match ($descriptionColor) {
|
||||
'gray' => 'text-gray-400 dark:text-gray-500',
|
||||
default => 'text-custom-500',
|
||||
},
|
||||
]);
|
||||
|
||||
$descriptionIconStyles = \Illuminate\Support\Arr::toCssStyles([
|
||||
\Filament\Support\get_color_css_variables(
|
||||
$descriptionColor,
|
||||
shades: [500],
|
||||
alias: 'widgets::stats-overview-widget.stat.description.icon',
|
||||
) => $descriptionColor !== 'gray',
|
||||
]);
|
||||
@endphp
|
||||
|
||||
<{!! $tag !!}
|
||||
@if ($url)
|
||||
{{ \Filament\Support\generate_href_html($url, $shouldOpenUrlInNewTab()) }}
|
||||
@endif
|
||||
{{
|
||||
$getExtraAttributeBag()
|
||||
->class([
|
||||
'fi-wi-stats-overview-stat relative rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10',
|
||||
])
|
||||
}}
|
||||
>
|
||||
<div class="grid gap-y-2">
|
||||
<div class="flex items-center gap-x-2">
|
||||
@if ($icon = $getIcon())
|
||||
<x-filament::icon
|
||||
:icon="$icon"
|
||||
class="fi-wi-stats-overview-stat-icon h-5 w-5 text-gray-400 dark:text-gray-500"
|
||||
/>
|
||||
@endif
|
||||
|
||||
<span
|
||||
class="fi-wi-stats-overview-stat-label text-sm font-medium text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
{{ $getLabel() }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="fi-wi-stats-overview-stat-value text-3xl font-semibold tracking-tight text-gray-950 dark:text-white"
|
||||
>
|
||||
{{ $getValue() }}
|
||||
</div>
|
||||
|
||||
@if ($description = $getDescription())
|
||||
<div class="flex items-center gap-x-1">
|
||||
@if ($descriptionIcon && in_array($descriptionIconPosition, [IconPosition::Before, 'before']))
|
||||
<x-filament::icon
|
||||
:icon="$descriptionIcon"
|
||||
:class="$descriptionIconClasses"
|
||||
:style="$descriptionIconStyles"
|
||||
/>
|
||||
@endif
|
||||
|
||||
<span
|
||||
@class([
|
||||
'fi-wi-stats-overview-stat-description text-sm',
|
||||
match ($descriptionColor) {
|
||||
'gray' => 'text-gray-500 dark:text-gray-400',
|
||||
default => 'fi-color-custom text-custom-600 dark:text-custom-400',
|
||||
},
|
||||
is_string($descriptionColor) ? "fi-color-{$descriptionColor}" : null,
|
||||
])
|
||||
@style([
|
||||
\Filament\Support\get_color_css_variables(
|
||||
$descriptionColor,
|
||||
shades: [400, 600],
|
||||
alias: 'widgets::stats-overview-widget.stat.description',
|
||||
) => $descriptionColor !== 'gray',
|
||||
])
|
||||
>
|
||||
{{ $description }}
|
||||
</span>
|
||||
|
||||
@if ($descriptionIcon && in_array($descriptionIconPosition, [IconPosition::After, 'after']))
|
||||
<x-filament::icon
|
||||
:icon="$descriptionIcon"
|
||||
:class="$descriptionIconClasses"
|
||||
:style="$descriptionIconStyles"
|
||||
/>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if ($chart = $getChart())
|
||||
{{-- An empty function to initialize the Alpine component with until it's loaded with `ax-load`. This removes the need for `x-ignore`, allowing the chart to be updated via Livewire polling. --}}
|
||||
<div x-data="{ statsOverviewStatChart: function () {} }">
|
||||
<div
|
||||
@if (FilamentView::hasSpaMode())
|
||||
ax-load="visible"
|
||||
@else
|
||||
ax-load
|
||||
@endif
|
||||
ax-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('stats-overview/stat/chart', 'filament/widgets') }}"
|
||||
x-data="statsOverviewStatChart({
|
||||
dataChecksum: @js($dataChecksum),
|
||||
labels: @js(array_keys($chart)),
|
||||
values: @js(array_values($chart)),
|
||||
})"
|
||||
@class([
|
||||
'fi-wi-stats-overview-stat-chart absolute inset-x-0 bottom-0 overflow-hidden rounded-b-xl',
|
||||
match ($chartColor) {
|
||||
'gray' => null,
|
||||
default => 'fi-color-custom',
|
||||
},
|
||||
is_string($chartColor) ? "fi-color-{$chartColor}" : null,
|
||||
])
|
||||
@style([
|
||||
\Filament\Support\get_color_css_variables(
|
||||
$chartColor,
|
||||
shades: [50, 400, 500],
|
||||
alias: 'widgets::stats-overview-widget.stat.chart',
|
||||
) => $chartColor !== 'gray',
|
||||
])
|
||||
>
|
||||
<canvas x-ref="canvas" class="h-6"></canvas>
|
||||
|
||||
<span
|
||||
x-ref="backgroundColorElement"
|
||||
@class([
|
||||
match ($chartColor) {
|
||||
'gray' => 'text-gray-100 dark:text-gray-800',
|
||||
default => 'text-custom-50 dark:text-custom-400/10',
|
||||
},
|
||||
])
|
||||
></span>
|
||||
|
||||
<span
|
||||
x-ref="borderColorElement"
|
||||
@class([
|
||||
match ($chartColor) {
|
||||
'gray' => 'text-gray-400',
|
||||
default => 'text-custom-500 dark:text-custom-400',
|
||||
},
|
||||
])
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</{!! $tag !!}>
|
||||
7
vendor/filament/widgets/resources/views/table-widget.blade.php
vendored
Normal file
7
vendor/filament/widgets/resources/views/table-widget.blade.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<x-filament-widgets::widget class="fi-wi-table">
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Widgets\View\WidgetsRenderHook::TABLE_WIDGET_START, scopes: static::class) }}
|
||||
|
||||
{{ $this->table }}
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Widgets\View\WidgetsRenderHook::TABLE_WIDGET_END, scopes: static::class) }}
|
||||
</x-filament-widgets::widget>
|
||||
Reference in New Issue
Block a user