Add admin dashboard

This commit is contained in:
mashirozx 2021-07-13 16:15:03 +08:00
parent 392aa03bd2
commit 4c981aab8e
12 changed files with 237 additions and 22 deletions

View File

@ -2,10 +2,10 @@
"html": { "html": {
"snippets": { "snippets": {
"divc": "div[class=${1}]", "divc": "div[class=${1}]",
"icon": "icon[name=${1}]",
"view": "div[class=${1}]", "view": "div[class=${1}]",
"text": "span[class=\"text\"]", "text": "span[class=\"text\"]",
"image": "Image[src=${1} placeholder=${2} :avatar=\"false\" alt=${2} :draggable=\"false\"]" "image": "Image[src=${1} placeholder=${2} :avatar=\"false\" alt=${2} :draggable=\"false\"]",
"icon": "UiIcon[name=${1} :width=\"100%\" :height=\"100%\"]"
} }
} }
} }

View File

@ -10,7 +10,8 @@ require_once(__DIR__ . '/loader.php');
new \Sakura\Helpers\SetupHelper(); new \Sakura\Helpers\SetupHelper();
new \Sakura\Helpers\WhoopsHelper(); new \Sakura\Helpers\WhoopsHelper();
new \Sakura\Helpers\ViteRequireHelper(); new \Sakura\Helpers\ViteHelper();
new \Sakura\Helpers\AdminPageHelper();
new \Sakura\Helpers\CustomMenuMetaFieldsHelper(); new \Sakura\Helpers\CustomMenuMetaFieldsHelper();
new \Sakura\Helpers\CommentHelper(); new \Sakura\Helpers\CommentHelper();
new \Sakura\Helpers\PostQueryHelper('post'); new \Sakura\Helpers\PostQueryHelper('post');

View File

@ -0,0 +1,86 @@
<?php
namespace Sakura\Helpers;
use Sakura\Helpers\ViteHelper;
use Sakura\Controllers\InitStateController;
class AdminPageHelper
{
public static $version = SAKURA_VERSION;
public static $text_domain = SAKURA_TEXT_DOMAIN;
public $page_title;
public $menu_title;
public $menu_slug;
public function __construct()
{
$this->page_title = __('Sakura theme options', self::$text_domain);
$this->menu_title = __('Sakura Options', self::$text_domain);
$this->menu_slug = __('sakura_options', self::$text_domain);
add_action('admin_menu', [$this, 'add_theme_page']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']);
}
public function add_theme_page()
{
add_theme_page($this->page_title, $this->menu_title, 'edit_theme_options', $this->menu_slug, function () {
$template = new TemplateHelper();
echo $template->load('admin-page-helper.twig')->renderBlock('admin_app', []);
});
}
public function enqueue_scripts($hook)
{
if ("appearance_page_{$this->menu_slug}" === $hook) {
$this->enqueue_common_scripts();
// $this->enqueue_development_scripts();
$this->enqueue_production_scripts();
}
}
public function enqueue_development_scripts()
{
wp_enqueue_script('[type:module]vite-client', ViteHelper::$development_host . '/@vite/client', array(), null, false);
wp_enqueue_script('[type:module]dev-main', ViteHelper::$development_host . '/src/admin/main.ts', array(), null, true);
wp_localize_script('[type:module]dev-main', 'InitState', (new InitStateController())->get_initial_state());
}
public function enqueue_production_scripts()
{
$entry_key = 'src/admin/main.ts';
$assets_base_path = get_template_directory_uri() . '/assets/dist/';
$manifest = ViteHelper::get_manifest_file();
// <script type="module" crossorigin src="http://localhost:9000/assets/index.36b06f45.js"></script>
wp_enqueue_script('[type:module]chunk-vendors.js', $assets_base_path . $manifest[$entry_key]['file'], array(), null, false);
wp_localize_script('[type:module]chunk-vendors.js', 'InitState', (new InitStateController())->get_initial_state());
// <link rel="modulepreload" href="http://localhost:9000/assets/vendor.b3a324ba.js">
foreach ($manifest[$entry_key]['imports'] as $index => $import) {
wp_enqueue_style("[ref:modulepreload]chunk-vendors{$import}", $assets_base_path . $manifest[$import]['file']);
if (empty($manifest[$import]['css'])) {
continue;
}
foreach ($manifest[$import]['css'] as $css_index => $css_path) {
wp_enqueue_style("sakura-chunk-{$import}-{$css_index}.css", $assets_base_path . $css_path);
}
}
// <link rel="stylesheet" href="http://localhost:9000/assets/index.2c78c25a.css">
foreach ($manifest[$entry_key]['css'] as $index => $path) {
wp_enqueue_style("sakura-chunk-{$index}.css", $assets_base_path . $path);
}
}
public function enqueue_common_scripts()
{
wp_enqueue_style('style.css', get_template_directory_uri() . '/style.css');
wp_enqueue_style('fontawesome-free', 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css');
}
}

View File

@ -2,13 +2,13 @@
namespace Sakura\Helpers; namespace Sakura\Helpers;
use Sakura\Controllers; use Sakura\Controllers\InitStateController;
class ViteRequireHelper class ViteHelper
{ {
// TODO: use a common .env file // TODO: use a common .env file
// public $development_host = 'http://192.168.28.26:9000'; // public $development_host = 'http://192.168.28.26:9000';
public $development_host = 'http://127.0.0.1:9000'; public static $development_host = 'http://127.0.0.1:9000';
function __construct() function __construct()
{ {
@ -22,25 +22,37 @@ class ViteRequireHelper
public function enqueue_development_scripts() public function enqueue_development_scripts()
{ {
wp_enqueue_script('[type:module]vite-client', $this->development_host . '/@vite/client', array(), null, false); wp_enqueue_script('[type:module]vite-client', self::$development_host . '/@vite/client', array(), null, false);
wp_enqueue_script('[type:module]dev-main', $this->development_host . '/src/main.ts', array(), null, true);
wp_enqueue_script('[type:module]dev-main', self::$development_host . '/src/main.ts', array(), null, true);
wp_localize_script('[type:module]dev-main', 'InitState', (new InitStateController())->get_initial_state());
} }
public function enqueue_production_scripts() public function enqueue_production_scripts()
{ {
$entry_key = 'src/main.ts';
$assets_base_path = get_template_directory_uri() . '/assets/dist/'; $assets_base_path = get_template_directory_uri() . '/assets/dist/';
$manifest = $this->get_manifest_file(); $manifest = $this->get_manifest_file();
// <script type="module" crossorigin src="http://localhost:9000/assets/index.36b06f45.js"></script> // <script type="module" crossorigin src="http://localhost:9000/assets/index.36b06f45.js"></script>
wp_enqueue_script('[type:module]chunk-vendors.js', $assets_base_path . $manifest['src/main.ts']['file'], array(), null, false); wp_enqueue_script('[type:module]chunk-entrance.js', $assets_base_path . $manifest[$entry_key]['file'], array(), null, false);
wp_localize_script('[type:module]chunk-entrance.js', 'InitState', (new InitStateController())->get_initial_state());
// <link rel="modulepreload" href="http://localhost:9000/assets/vendor.b3a324ba.js"> // <link rel="modulepreload" href="http://localhost:9000/assets/vendor.b3a324ba.js">
foreach ($manifest['src/main.ts']['imports'] as $index => $import) { foreach ($manifest[$entry_key]['imports'] as $index => $import) {
wp_enqueue_style("[ref:modulepreload]chunk-vendors-{$index}.js", $assets_base_path . $manifest[$import]['file']); wp_enqueue_style("[ref:modulepreload]chunk-vendors{$import}", $assets_base_path . $manifest[$import]['file']);
if (empty($manifest[$import]['css'])) {
continue;
}
foreach ($manifest[$import]['css'] as $css_index => $css_path) {
wp_enqueue_style("sakura-chunk-{$import}-{$css_index}.css", $assets_base_path . $css_path);
}
} }
// <link rel="stylesheet" href="http://localhost:9000/assets/index.2c78c25a.css"> // <link rel="stylesheet" href="http://localhost:9000/assets/index.2c78c25a.css">
foreach ($manifest['src/main.ts']['css'] as $index => $path) { foreach ($manifest[$entry_key]['css'] as $index => $path) {
wp_enqueue_style("sakura-chunk-{$index}.css", $assets_base_path . $path); wp_enqueue_style("sakura-chunk-{$index}.css", $assets_base_path . $path);
} }
} }
@ -52,14 +64,14 @@ class ViteRequireHelper
wp_enqueue_style('fontawesome-free', 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css'); wp_enqueue_style('fontawesome-free', 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css');
// TODO: don't use vue.js as handler // TODO: don't use vue.js as handler
wp_enqueue_script('vue.js', 'https://unpkg.com/vue@next', array(), false, false); // wp_enqueue_script('vue.js', 'https://unpkg.com/vue@next', array(), false, false);
wp_localize_script('vue.js', 'InitState', (new Controllers\InitStateController())->get_initial_state()); // wp_localize_script('vue.js', 'InitState', (new InitStateController())->get_initial_state());
wp_enqueue_script('recaptcha', 'https://www.recaptcha.net/recaptcha/api.js?render=6LdKhX8bAAAAAF5HJprXtKvg3nfBJMfgd2o007PN', array(), false, true); wp_enqueue_script('recaptcha', 'https://www.recaptcha.net/recaptcha/api.js?render=6LdKhX8bAAAAAF5HJprXtKvg3nfBJMfgd2o007PN', array(), false, true);
} }
public function script_tag_filter($tag, $handle, $src) public static function script_tag_filter($tag, $handle, $src)
{ {
if (preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle)) { if (preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle)) {
preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle, $matches, PREG_OFFSET_CAPTURE); preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle, $matches, PREG_OFFSET_CAPTURE);
@ -69,7 +81,7 @@ class ViteRequireHelper
return $tag; return $tag;
} }
public function style_tag_filter($tag, $handle, $src) public static function style_tag_filter($tag, $handle, $src)
{ {
if (preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle)) { if (preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle)) {
preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle, $matches, PREG_OFFSET_CAPTURE); preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle, $matches, PREG_OFFSET_CAPTURE);
@ -79,7 +91,7 @@ class ViteRequireHelper
return $tag; return $tag;
} }
public function get_manifest_file() public static function get_manifest_file()
{ {
$manifest = file_get_contents(__DIR__ . '/../assets/dist/manifest.json'); $manifest = file_get_contents(__DIR__ . '/../assets/dist/manifest.json');
return json_decode($manifest, true); return json_decode($manifest, true);

View File

@ -0,0 +1,21 @@
<?php
namespace Sakura\Routers;
use Sakura\Helpers\TemplateHelper;
class AdminRouter
{
public function __construct()
{
add_action('admin_menu', [$this, 'add_theme_page']);
}
public function add_theme_page()
{
add_theme_page('page_title', 'menu-title', 'edit_theme_options', 'menu-slug', function () {
$template = new TemplateHelper();
echo $template->load('admin-rouer.twig')->renderBlock('admin_app', []);
});
}
}

View File

@ -0,0 +1,5 @@
{% block admin_app %}
<div id="app" class="sakura-options-page__app">
Loading
</div>
{% endblock %}

View File

@ -65,6 +65,7 @@
"@types/uuid": "^8.3.1", "@types/uuid": "^8.3.1",
"@typescript-eslint/eslint-plugin": "^4.28.3", "@typescript-eslint/eslint-plugin": "^4.28.3",
"@typescript-eslint/parser": "^4.28.3", "@typescript-eslint/parser": "^4.28.3",
"@vitejs/plugin-legacy": "^1.4.4",
"@vitejs/plugin-vue": "^1.2.5", "@vitejs/plugin-vue": "^1.2.5",
"@vue/compiler-sfc": "^3.1.4", "@vue/compiler-sfc": "^3.1.4",
"@vue/eslint-config-prettier": "^6.0.0", "@vue/eslint-config-prettier": "^6.0.0",

View File

@ -1,4 +1,24 @@
<template> <template>
<h1>wp-admin</h1> <div class="app__wrapper">
<Image src="https://view.moezx.cc/images/2021/07/08/121a00d4db8142384418382abf529364.gif"></Image> <Layout></Layout>
</div>
</template> </template>
<script lang="ts">
import { defineComponent } from 'vue'
import Layout from './Layout.vue'
export default defineComponent({
components: { Layout },
})
</script>
<style lang="scss">
.sakura-options-page__app {
width: calc(100% - 20px);
padding: 20px 20px 20px 0;
> .app__wrapper {
background: yellowgreen;
}
}
</style>

26
src/admin/Layout.vue Normal file
View File

@ -0,0 +1,26 @@
<template>
<div class="layout">
<div class="wrapper">
<Image
src="https://view.moezx.cc/images/2021/07/08/121a00d4db8142384418382abf529364.gif"
></Image>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import Image from '@/components/image/Image.vue'
export default defineComponent({
components: { Image },
setup() {},
})
</script>
<style lang="scss" scoped>
.wrapper {
width: 200px;
height: 200px;
}
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="image__container"> <div :class="['image__container', state]">
<img <img
:class="['image', state]" :class="['image', state]"
:src="$props.src" :src="$props.src"
@ -10,7 +10,7 @@
/> />
<img <img
v-if="placeholderImage" v-if="placeholderImage"
class="default" :class="['default', state]"
:src="placeholderImage" :src="placeholderImage"
:alt="$props.alt" :alt="$props.alt"
:draggable="$props.draggable" :draggable="$props.draggable"
@ -69,7 +69,10 @@ export default defineComponent({
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: relative;
&.loading,
&.error {
@include skeleton.skeleton-loading; @include skeleton.skeleton-loading;
}
.image, .image,
.default { .default {
width: 100%; width: 100%;
@ -84,5 +87,10 @@ export default defineComponent({
visibility: hidden; visibility: hidden;
} }
} }
.default {
.load {
visibility: hidden;
}
}
} }
</style> </style>

View File

@ -1,5 +1,6 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
// import legacy from '@vitejs/plugin-legacy'
import path from 'path' import path from 'path'
import svgicon from 'vite-plugin-svgicon' import svgicon from 'vite-plugin-svgicon'
@ -17,6 +18,9 @@ export default defineConfig({
svgicon({ svgicon({
include: ['**/icons/**/*.svg'], include: ['**/icons/**/*.svg'],
}), }),
// legacy({
// targets: ['defaults', 'not IE 11'],
// }),
], ],
server: { server: {
host: '0.0.0.0', host: '0.0.0.0',

View File

@ -296,6 +296,11 @@
"@babel/helper-simple-access" "^7.14.5" "@babel/helper-simple-access" "^7.14.5"
babel-plugin-dynamic-import-node "^2.3.3" babel-plugin-dynamic-import-node "^2.3.3"
"@babel/standalone@^7.14.7":
version "7.14.7"
resolved "https://registry.nlark.com/@babel/standalone/download/@babel/standalone-7.14.7.tgz#68635da005d6a34a0259599e0720d2e73133ecc3"
integrity sha1-aGNdoAXWo0oCWVmeByDS5zEz7MM=
"@babel/template@^7.14.5", "@babel/template@^7.3.3": "@babel/template@^7.14.5", "@babel/template@^7.3.3":
version "7.14.5" version "7.14.5"
resolved "https://registry.nlark.com/@babel/template/download/@babel/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" resolved "https://registry.nlark.com/@babel/template/download/@babel/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
@ -1408,6 +1413,17 @@
"@typescript-eslint/types" "4.28.3" "@typescript-eslint/types" "4.28.3"
eslint-visitor-keys "^2.0.0" eslint-visitor-keys "^2.0.0"
"@vitejs/plugin-legacy@^1.4.4":
version "1.4.4"
resolved "https://registry.nlark.com/@vitejs/plugin-legacy/download/@vitejs/plugin-legacy-1.4.4.tgz#a13bcfdf053f219fd8db6199e0d19c87b3d12994"
integrity sha1-oTvP3wU/IZ/Y22GZ4NGch7PRKZQ=
dependencies:
"@babel/standalone" "^7.14.7"
core-js "^3.15.2"
magic-string "^0.25.7"
regenerator-runtime "^0.13.7"
systemjs "^6.10.2"
"@vitejs/plugin-vue@^1.2.5": "@vitejs/plugin-vue@^1.2.5":
version "1.2.5" version "1.2.5"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-1.2.5.tgz#ef7dc4a92e53fe866b54bcc1266788513262ac09" resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-1.2.5.tgz#ef7dc4a92e53fe866b54bcc1266788513262ac09"
@ -2341,6 +2357,11 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
dependencies: dependencies:
safe-buffer "~5.1.1" safe-buffer "~5.1.1"
core-js@^3.15.2:
version "3.15.2"
resolved "https://registry.nlark.com/core-js/download/core-js-3.15.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcore-js%2Fdownload%2Fcore-js-3.15.2.tgz#740660d2ff55ef34ce664d7e2455119c5bdd3d61"
integrity sha1-dAZg0v9V7zTOZk1+JFURnFvdPWE=
core-util-is@~1.0.0: core-util-is@~1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" resolved "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@ -5695,6 +5716,11 @@ redent@^2.0.0:
indent-string "^3.0.0" indent-string "^3.0.0"
strip-indent "^2.0.0" strip-indent "^2.0.0"
regenerator-runtime@^0.13.7:
version "0.13.7"
resolved "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha1-ysLazIoepnX+qrrriugziYrkb1U=
regexpp@^3.1.0: regexpp@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.npm.taobao.org/regexpp/download/regexpp-3.1.0.tgz" resolved "https://registry.npm.taobao.org/regexpp/download/regexpp-3.1.0.tgz"
@ -6278,6 +6304,11 @@ symbol-tree@^3.2.4:
resolved "https://registry.npm.taobao.org/symbol-tree/download/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" resolved "https://registry.npm.taobao.org/symbol-tree/download/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha1-QwY30ki6d+B4iDlR+5qg7tfGP6I= integrity sha1-QwY30ki6d+B4iDlR+5qg7tfGP6I=
systemjs@^6.10.2:
version "6.10.2"
resolved "https://registry.nlark.com/systemjs/download/systemjs-6.10.2.tgz#c9870217bddf9cfd25d12d4fcd1989541ef1207c"
integrity sha1-yYcCF73fnP0l0S1PzRmJVB7xIHw=
table@^6.0.9: table@^6.0.9:
version "6.7.1" version "6.7.1"
resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2"