初始化

This commit is contained in:
2026-08-08 18:27:38 +08:00
parent efc150c937
commit 060eb79c09
336 changed files with 24613 additions and 15 deletions
+46
View File
@@ -0,0 +1,46 @@
@props(['name', 'size' => 20, 'class' => ''])
@php
$icons = [
'home' => '<path d="M3 11.5 12 4l9 7.5"/><path d="M5 10v10h14V10"/>',
'user' => '<circle cx="12" cy="8" r="4"/><path d="M4 20a8 8 0 0 1 16 0"/>',
'mail' => '<rect x="3" y="6" width="18" height="12" rx="2"/><path d="M3 7l9 6 9-6"/>',
'phone' => '<path d="M5 4h4l2 5-3 2a12 12 0 0 0 5 5l2-3 5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2z"/>',
'search' => '<circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/>',
'send' => '<path d="M3 11l18-8-8 18-2-8z"/>',
'check' => '<path d="M5 13l4 4 10-10"/>',
'alert' => '<path d="M10.3 4.3 2.5 18a2 2 0 0 0 1.7 3h15.6a2 2 0 0 0 1.7-3L13.7 4.3a2 2 0 0 0-3.4 0z"/><path d="M12 9v4"/><path d="M12 17h.01"/>',
'arrow' => '<path d="M5 12h14"/><path d="M13 6l6 6-6 6"/>',
'shield' => '<path d="M12 3v18"/><path d="M5 7l7-4 7 4v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"/>',
'menu' => '<path d="M4 7h16"/><path d="M4 12h16"/><path d="M4 17h16"/>',
'close' => '<path d="M6 6l12 12"/><path d="M18 6 6 18"/>',
'box' => '<path d="M3 7l9-4 9 4v10l-9 4-9-4z"/><path d="M3 7l9 4 9-4"/><path d="M12 11v10"/>',
'doc' => '<path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/><path d="M9 12h6"/><path d="M9 16h6"/>',
'book' => '<path d="M5 4h11a2 2 0 0 1 2 2v14H7a2 2 0 0 1-2-2z"/><path d="M5 4v14"/>',
'chat' => '<path d="M4 5h16v11H9l-5 4z"/>',
'pin' => '<path d="M12 21s7-6 7-11a7 7 0 1 0-14 0c0 5 7 11 7 11z"/><circle cx="12" cy="10" r="2.5"/>',
'lock' => '<rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/>',
'grid' => '<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>',
'tag' => '<path d="M3 12V4h8l9 9-8 8z"/><circle cx="8" cy="8" r="1.5"/>',
'users' => '<circle cx="9" cy="8" r="3.5"/><path d="M3 20a6 6 0 0 1 12 0"/><path d="M16 4a3.5 3.5 0 0 1 0 7"/><path d="M17 14a6 6 0 0 1 4 6"/>',
'plus' => '<path d="M12 5v14"/><path d="M5 12h14"/>',
'edit' => '<path d="M4 20h4L19 9l-4-4L4 16z"/><path d="M14 5l4 4"/>',
'trash' => '<path d="M4 7h16"/><path d="M9 7V4h6v3"/><path d="M6 7l1 13h10l1-13"/>',
'settings' => '<circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M4.9 4.9l2.1 2.1M17 17l2.1 2.1M19.1 4.9 17 7M7 17l-2.1 2.1"/>',
'database' => '<ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v14c0 1.7 3.6 3 8 3s8-1.3 8-3V5"/><path d="M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/>',
'compass' => '<circle cx="12" cy="12" r="9"/><path d="M15 9l-2.5 5L7 16.5 9.5 11z"/>',
'newspaper' => '<path d="M4 4h13v16H6a2 2 0 0 1-2-2z"/><path d="M17 8h3v10a2 2 0 0 1-2 2"/><path d="M7 8h7M7 12h7M7 16h5"/>',
'zap' => '<path d="M13 2 4 14h7l-1 8 9-12h-7z"/>',
'cpu' => '<rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 2v3M15 2v3M9 19v3M15 19v3M2 9h3M2 15h3M19 9h3M19 15h3"/>',
'layers' => '<path d="M12 3 3 8l9 5 9-5z"/><path d="M3 13l9 5 9-5"/>',
'globe' => '<circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><path d="M12 3a14 14 0 0 1 0 18 14 14 0 0 1 0-18z"/>',
'link' => '<path d="M9 12h6"/><path d="M10 8H7a4 4 0 0 0 0 8h3"/><path d="M14 8h3a4 4 0 0 1 0 8h-3"/>',
'arrowUpRight' => '<path d="M7 17 17 7"/><path d="M8 7h9v9"/>',
'wechat' => '<path d="M8 4C4.5 4 2 6.4 2 9.2c0 1.6.9 3 2.3 4L4 16l3.2-1.6c.6.2 1.3.3 2 .3"/><path d="M21 13.5c0-2.1-2-3.8-4.4-3.8s-4.4 1.7-4.4 3.8 2 3.8 4.4 3.8c.5 0 1-.1 1.5-.2L20 18l-.5-1.5c1.1-.7 1.5-1.7 1.5-3z"/>',
'weibo' => '<circle cx="9" cy="14" r="5"/><path d="M16 6a4 4 0 0 1 4 4"/><path d="M15.5 3.5a6 6 0 0 1 6 6"/>',
'linkedin' => '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M7 10v7M7 7v.01M11 17v-4a2 2 0 0 1 4 0v4M11 10v7"/>',
];
$paths = $icons[$name] ?? $icons['home'];
@endphp
<svg xmlns="http://www.w3.org/2000/svg" width="{{ $size }}" height="{{ $size }}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="{{ $class }}" aria-hidden="true" role="img">{!! $paths !!}</svg>
@@ -0,0 +1,8 @@
@props(['user' => null])
@if ($user)
@php $l = $user->level(); @endphp
<span class="inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-semibold @if($l <= 1) bg-surface-2 text-muted @elseif($l === 2) bg-info-soft text-info @elseif($l === 3) bg-primary-soft text-primary @elseif($l === 4) bg-warning-soft text-warning @else bg-danger-soft text-danger @endif" title="会员等级 L{{ $l }}">
L{{ $l }} {{ $user->levelName() }}
</span>
@endif
@@ -0,0 +1,95 @@
@props(['name' => 'body', 'value' => ''])
{{-- Quill 富文本编辑器(本地化,零构建,不依赖外部 CDN)。提交前把 HTML 同步进隐藏 textarea。 --}}
<link rel="stylesheet" href="{{ asset('vendor/quill/quill.snow.css') }}">
<div class="rich-editor">
<div id="quill-{{ $name }}"></div>
</div>
<textarea name="{{ $name }}" id="quill-input-{{ $name }}" hidden>{{ $value }}</textarea>
<script src="{{ asset('vendor/quill/quill.js') }}"></script>
<script>
(function () {
var FIELD = '{{ $name }}';
var input = document.getElementById('quill-input-' + FIELD);
if (typeof Quill === 'undefined' || !input) return;
var quill = new Quill('#quill-' + FIELD, {
theme: 'snow',
placeholder: '在此撰写文章正文,支持标题、列表、引用、代码与插入图片…',
modules: {
toolbar: {
container: [
[{ header: [1, 2, 3, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ list: 'ordered' }, { list: 'bullet' }],
['blockquote', 'code-block'],
['link', 'image'],
['clean']
],
handlers: { image: imageHandler }
}
}
});
quill.root.innerHTML = input.value || '';
var form = input.closest('form');
if (form) {
form.addEventListener('submit', function () {
input.value = quill.root.innerHTML;
});
}
function imageHandler() {
var fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'image/*';
fileInput.click();
fileInput.onchange = function () {
if (!fileInput.files.length) return;
var fd = new FormData();
fd.append('file', fileInput.files[0]);
var token = (document.querySelector('input[name=_token]') || {}).value || '';
fetch('{{ route('upload') }}', {
method: 'POST',
headers: { 'X-CSRF-TOKEN': token },
body: fd
})
.then(function (r) { return r.json(); })
.then(function (d) {
if (d.url) {
var range = quill.getSelection(true);
quill.insertEmbed(range.index, 'image', d.url, 'user');
} else if (d.errors && d.errors.file) {
alert(d.errors.file[0]);
} else {
alert('图片上传失败,请重试');
}
})
.catch(function () { alert('图片上传失败,请重试'); });
};
}
// 通用文件上传(封面图等),供表单内上传按钮 onclick="uploadFile('cover')" 调用
window.uploadFile = function (field) {
var fileInput = document.getElementById(field + '-file');
if (!fileInput || !fileInput.files.length) { alert('请先选择文件'); return; }
var fd = new FormData();
fd.append('file', fileInput.files[0]);
var token = (document.querySelector('input[name=_token]') || {}).value || '';
fetch('{{ route('upload') }}', {
method: 'POST',
headers: { 'X-CSRF-TOKEN': token },
body: fd
})
.then(function (r) { return r.json(); })
.then(function (d) {
if (d.url) { document.getElementById(field + '-url').value = d.url; }
else if (d.errors && d.errors.file) { alert(d.errors.file[0]); }
else { alert('上传失败,请重试'); }
})
.catch(function () { alert('上传失败,请重试'); });
};
})();
</script>