🚩 新增插件模板功能
@ -3,6 +3,7 @@
|
||||
|
||||
### 🎉 What's this?
|
||||
这是一款`在线工具箱`程序,您可以通过安装扩展增强她的功能
|
||||
通过插件模板的功能,您也可以把她当做网页导航来使用~
|
||||
觉得该项目不错的可以给个`Star`~
|
||||
|
||||
### 😺 演示地址
|
||||
@ -17,7 +18,9 @@
|
||||
> 严禁用于非法用途
|
||||
|
||||
### 😺 文档
|
||||
[插件编写](docs/Plugin.md)
|
||||
[插件编写](docs/Plugin.md)
|
||||
[Github Oauth 配置](docs/Github_Oauth.md)
|
||||
[Plugin Template 使用](docs/Plugin_Template.md)
|
||||
|
||||
### 🎊 环境要求
|
||||
|
||||
|
||||
@ -80,6 +80,7 @@ class Plugin extends BaseController
|
||||
'title',
|
||||
'enable',
|
||||
'weight',
|
||||
'template',
|
||||
])->data($params)->save();
|
||||
return msg('ok', 'success', $plugin);
|
||||
}
|
||||
@ -117,6 +118,7 @@ class Plugin extends BaseController
|
||||
'title',
|
||||
'enable',
|
||||
'weight',
|
||||
'template',
|
||||
])->data($params)->save();
|
||||
return msg('ok', 'success', $plugin);
|
||||
}
|
||||
|
||||
@ -72,8 +72,18 @@ class System extends BaseController
|
||||
array_push($arr, basename($v));
|
||||
}
|
||||
}
|
||||
return msg('ok', 'success', $arr);
|
||||
|
||||
|
||||
}
|
||||
public function plugin_templates()
|
||||
{
|
||||
$glob = glob(template_path_get() . '/template/*');
|
||||
$arr = [];
|
||||
foreach ($glob as $v) {
|
||||
if (is_file($v)) {
|
||||
array_push($arr, basename($v,'.html'));
|
||||
}
|
||||
}
|
||||
return msg('ok', 'success', $arr);
|
||||
|
||||
}
|
||||
|
||||
@ -119,6 +119,7 @@ class Plugin
|
||||
$model->config = [];
|
||||
$model->category_id = 0;
|
||||
$model->request_count = 0;
|
||||
$model->template = 'default';
|
||||
}
|
||||
if (is_file($this->pluginPath . '/logo.png')) {
|
||||
$logoFilename = plugin_logo_path_get($this->pluginClass);
|
||||
|
||||
@ -6,6 +6,7 @@ namespace app\model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $weight 权重
|
||||
* @property string $create_time 安装时间
|
||||
* @property string $title 标题
|
||||
* @property string $update_time 更新时间
|
||||
|
||||
@ -10,14 +10,17 @@ use think\Model;
|
||||
* Class app\model\Plugin
|
||||
*
|
||||
* @property int $category_id 分类
|
||||
* @property int $enable 是否启用
|
||||
* @property int $id
|
||||
* @property int $request_count 接口请求次数
|
||||
* @property int $weight 权重
|
||||
* @property string $alias 插件名
|
||||
* @property string $class 插件类
|
||||
* @property string $config 配置信息
|
||||
* @property string $create_time 安装时间
|
||||
* @property string $desc 插件描述
|
||||
* @property string $logo 插件logo
|
||||
* @property string $template
|
||||
* @property string $title 插件标题
|
||||
* @property string $update_time 更新时间
|
||||
* @property string $version 版本
|
||||
|
||||
@ -12,6 +12,7 @@ namespace app\model;
|
||||
* @property int $request_count 接口请求次数
|
||||
* @property string $create_time 安装时间
|
||||
* @property string $update_time 更新时间
|
||||
* @property-read \app\model\Plugin $plugin
|
||||
*/
|
||||
class Request extends Base
|
||||
{
|
||||
|
||||
@ -3,4 +3,4 @@
|
||||
// | 版本号
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
define('VERSION', 'v1.2');
|
||||
define('VERSION', 'v1.3');
|
||||
12
docs/Github_Oauth.md
Normal file
@ -0,0 +1,12 @@
|
||||
## Github Oauth 配置
|
||||
* 打开Github,并且登录你的github账号
|
||||
* 打开:https://github.com/settings/developers
|
||||
|
||||
### 创建一个Oauth APP
|
||||
|
||||

|
||||
#### 填写APP信息
|
||||

|
||||
#### 获取`Client ID`和`Client secrets`
|
||||

|
||||
#### 最后在安装界面填入刚刚得到的的`Client ID`和`Client secrets`即可完成`Oauth`配置
|
||||
20
docs/Plugin_Template.md
Normal file
@ -0,0 +1,20 @@
|
||||
## Plugin Template 使用
|
||||
### 添加插件
|
||||

|
||||
|
||||
### 插件配置信息填入下方`JSON`数据
|
||||
```json
|
||||
{
|
||||
"url":"https://www.aoaostar.com"
|
||||
}
|
||||
```
|
||||
### 成功演示
|
||||

|
||||
#### `redirect`亦是如此
|
||||
|
||||
## 添加新模板
|
||||
### 在`view/index/default/template`添加`pluto.html`
|
||||

|
||||
|
||||
### 添加成功之后,即可在后台看到新增的模板
|
||||

|
||||
BIN
docs/images/github_oauth_1.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
docs/images/github_oauth_2.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/images/github_oauth_3.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
docs/images/plugin_template_1.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/images/plugin_template_2.png
Normal file
|
After Width: | Height: | Size: 262 KiB |
BIN
docs/images/plugin_template_3.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
docs/images/plugin_template_4.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 979 KiB After Width: | Height: | Size: 1.9 MiB |
@ -80,6 +80,7 @@ CREATE TABLE `toolbox_plugin` (
|
||||
`enable` int(11) NOT NULL DEFAULT 1 COMMENT '是否启用',
|
||||
`request_count` int(11) NOT NULL DEFAULT 0 COMMENT '接口请求次数',
|
||||
`category_id` int(11) NOT NULL DEFAULT 0 COMMENT '分类',
|
||||
`template` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'default',
|
||||
`create_time` datetime NOT NULL COMMENT '安装时间',
|
||||
`update_time` datetime NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
@ -90,7 +91,7 @@ CREATE TABLE `toolbox_plugin` (
|
||||
-- ----------------------------
|
||||
-- Records of toolbox_plugin
|
||||
-- ----------------------------
|
||||
INSERT INTO `toolbox_plugin` VALUES (1, 'Hello,Pluto', '/static/icons/aoaostar_com_example.png', 'If you see this message, it means that your program is running properly', 'example', 'aoaostar_com\\example', '{}', 'v1.0', 0, 1, 0, 1, '2021-12-22 18:38:35', '2021-12-25 13:50:14');
|
||||
INSERT INTO `toolbox_plugin` VALUES (1, 'Hello,Pluto', '/static/icons/aoaostar_com_example.png', 'If you see this message, it means that your program is running properly', 'example', 'aoaostar_com\\example', '{}', 'v1.0', 0, 1, 0, 1, 'default', '2021-12-22 18:38:35', '2021-12-25 13:50:14');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for toolbox_request
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>傲星工具箱 - 后台管理中心</title>
|
||||
<title>后台管理中心 - 傲星工具箱</title>
|
||||
<meta name="keywords" content="傲星工具箱,在线工具箱,aoaostar,pluto">
|
||||
<meta name="description" content="这是一个非常Nice的在线工具箱">
|
||||
<meta name="renderer" content="webkit">
|
||||
|
||||
@ -149,6 +149,11 @@ const system_get = () => {
|
||||
const templates_get = () => {
|
||||
return httpGet('/master/system/templates')
|
||||
}
|
||||
|
||||
const plugin_templates_get = () => {
|
||||
return httpGet('/master/system/plugin_templates')
|
||||
}
|
||||
|
||||
const ota_check = () => {
|
||||
return httpGet('/master/ota/check')
|
||||
}
|
||||
|
||||
@ -21,6 +21,11 @@
|
||||
padding: .5rem;
|
||||
}
|
||||
|
||||
.ota-console {
|
||||
max-width: 600px;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -112,7 +117,8 @@
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '在线更新',
|
||||
area: ['600px', '400px'],
|
||||
area: ['85vw', '400px'],
|
||||
skin: 'ota-console',
|
||||
shade: 0.8,
|
||||
id: 'ota_update',
|
||||
content: `<div class="console" id="console"></div>`,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>layui</title>
|
||||
<title>插件管理</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
@ -118,6 +118,7 @@
|
||||
return '默认分组'
|
||||
}
|
||||
},
|
||||
{field: 'template', width: 100, title: '模板', sort: true, align: 'center'},
|
||||
{
|
||||
field: 'config', width: 150, title: '配置信息', align: 'center', templet: function (res) {
|
||||
return JSON.stringify(res.config, null, 4)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>layui</title>
|
||||
<title>添加插件</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
@ -29,7 +29,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">logo:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="logo" placeholder="请输入插件logo" value="/static/images/plugin_default.jpg"
|
||||
<input type="text" name="logo" placeholder="请输入插件logo" value="/static/images/plugin_default.png"
|
||||
lay-verify="required" lay-reqtext="插件logo不能为空"
|
||||
class="layui-input" required>
|
||||
<tip>插件Logo,无需多言</tip>
|
||||
@ -56,7 +56,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">插件版本号:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="version" placeholder="请填写插件版本号" value=""
|
||||
<input type="text" name="version" placeholder="请填写插件版本号" value="v1.0"
|
||||
lay-verify="required" lay-reqtext="插件版本号不能为空"
|
||||
class="layui-input" required>
|
||||
<tip>插件的版本号,例如:v1.0。</tip>
|
||||
@ -65,7 +65,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">插件权重:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="weight" placeholder="请填写插件权重" value=""
|
||||
<input type="number" name="weight" placeholder="请填写插件权重" value="0"
|
||||
lay-verify="required" lay-reqtext="插件权重不能为空"
|
||||
class="layui-input" required>
|
||||
<tip>填数字,数字越大排名越前。</tip>
|
||||
@ -74,7 +74,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">是否启用:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" value="1" name="enable" lay-skin="switch" lay-filter="switchTest" lay-text="ON|OFF">
|
||||
<input type="checkbox" value="1" name="enable" lay-skin="switch" lay-filter="switchTest" lay-text="ON|OFF" checked>
|
||||
<tip>禁用则不会在前台显示。</tip>
|
||||
</div>
|
||||
</div>
|
||||
@ -101,6 +101,15 @@
|
||||
<tip>插件描述信息,介绍一下这个插件是干什么的吧!</tip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">模板:</label>
|
||||
<div class="layui-input-block">
|
||||
<select lay-verify="required" name="template" id="templates" lay-verify="required" lay-reqtext="请选择模板">
|
||||
</select>
|
||||
<tip>默认运行本地插件,可通过设置模板实现iframe或redirect功能</tip>
|
||||
<tip>模板位于view/index/default/template目录</tip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="saveBtn">确认保存</button>
|
||||
@ -115,6 +124,14 @@
|
||||
{{# }); }}
|
||||
</select>
|
||||
</script>
|
||||
<script id="templates_tpl" type="text/html">
|
||||
<select lay-verify="required" name="category_id">
|
||||
<option value="default">default</option>
|
||||
{{# layui.each(d, function(index, item){ }}
|
||||
<option value="{{ item }}">{{ item }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
</script>
|
||||
<script src="../../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||
@ -125,15 +142,26 @@
|
||||
layer = layui.layer,
|
||||
laytpl = layui.laytpl,
|
||||
$ = layui.$;
|
||||
|
||||
layer.load(1)
|
||||
categories_get().then(res => {
|
||||
const getTpl = document.getElementById('categoies_tpl').innerHTML,
|
||||
let tasks = []
|
||||
tasks.push(categories_get().then(res => {
|
||||
var getTpl = document.getElementById('categoies_tpl').innerHTML,
|
||||
view = document.getElementById('categories');
|
||||
laytpl(getTpl).render(res.data.items, function (html) {
|
||||
view.innerHTML = html;
|
||||
form.render();
|
||||
});
|
||||
}).finally(() => {
|
||||
}))
|
||||
tasks.push(plugin_templates_get().then(res => {
|
||||
var getTpl = document.getElementById('templates_tpl').innerHTML,
|
||||
view = document.getElementById('templates');
|
||||
laytpl(getTpl).render(res.data, function (html) {
|
||||
view.innerHTML = html;
|
||||
form.render();
|
||||
});
|
||||
}))
|
||||
Promise.all(tasks).finally(() => {
|
||||
layer.closeAll('loading')
|
||||
})
|
||||
//监听提交
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>layui</title>
|
||||
<title>编辑插件</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
@ -35,7 +35,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">logo:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="logo" placeholder="请输入插件logo" value="/static/images/plugin_default.jpg"
|
||||
<input type="text" name="logo" placeholder="请输入插件logo" value="/static/images/plugin_default.png"
|
||||
lay-verify="required" lay-reqtext="插件logo不能为空"
|
||||
class="layui-input" required>
|
||||
<tip>插件Logo,无需多言</tip>
|
||||
@ -71,7 +71,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">插件权重:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="weight" placeholder="请填写插件权重" value=""
|
||||
<input type="number" name="weight" placeholder="请填写插件权重" value="0"
|
||||
lay-verify="required" lay-reqtext="插件权重不能为空"
|
||||
class="layui-input" required>
|
||||
<tip>填数字,数字越大排名越前。</tip>
|
||||
@ -108,6 +108,15 @@
|
||||
<tip>插件描述信息,介绍一下这个插件是干什么的吧!</tip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">模板:</label>
|
||||
<div class="layui-input-block">
|
||||
<select lay-verify="required" name="template" id="templates" lay-verify="required" lay-reqtext="请选择模板">
|
||||
</select>
|
||||
<tip>默认运行本地插件,可通过设置模板实现iframe或redirect功能</tip>
|
||||
<tip>模板位于view/index/default/template目录</tip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="saveBtn">确认保存</button>
|
||||
@ -122,6 +131,14 @@
|
||||
{{# }); }}
|
||||
</select>
|
||||
</script>
|
||||
<script id="templates_tpl" type="text/html">
|
||||
<select lay-verify="required" name="category_id">
|
||||
<option value="default">default</option>
|
||||
{{# layui.each(d, function(index, item){ }}
|
||||
<option value="{{ item }}">{{ item }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
</script>
|
||||
<script src="../../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||
@ -142,6 +159,14 @@
|
||||
form.render();
|
||||
});
|
||||
}))
|
||||
tasks.push(plugin_templates_get().then(res => {
|
||||
var getTpl = document.getElementById('templates_tpl').innerHTML,
|
||||
view = document.getElementById('templates');
|
||||
laytpl(getTpl).render(res.data, function (html) {
|
||||
view.innerHTML = html;
|
||||
form.render();
|
||||
});
|
||||
}))
|
||||
tasks.push(
|
||||
plugin_get(getQueryString('id')).then(res => {
|
||||
if (res.status === 'ok') {
|
||||
|
||||
@ -20,6 +20,7 @@ Route::group('master', function () {
|
||||
Route::delete('/category', 'Category/delete');
|
||||
|
||||
Route::get('/system/templates', 'System/templates');
|
||||
Route::get('/system/plugin_templates', 'System/plugin_templates');
|
||||
Route::get('/system/info', 'System/info');
|
||||
Route::get('/system', 'System/all');
|
||||
Route::post('/system', 'System/update');
|
||||
|
||||
@ -25,9 +25,13 @@ Route::get(':alias', function () {
|
||||
abort(404, '页面异常');
|
||||
}
|
||||
$template = plugin_template_path_get($path);
|
||||
$model = plugin_info_get($alias);
|
||||
View::assign([
|
||||
"plugin" => plugin_info_get($alias)
|
||||
"plugin" => $model
|
||||
]);
|
||||
if ($model->template !== 'default') {
|
||||
$template = template_path_get() . 'template/' . $model->template . '.html';
|
||||
}
|
||||
return view($template);
|
||||
})->pattern(['alias' => '[\w|\-/]+'])
|
||||
->middleware(\app\middleware\View::class);
|
||||
4
runtime/.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
*
|
||||
!.gitignore
|
||||
!.gitignore
|
||||
!update
|
||||
!update/**
|
||||
5
runtime/update/sql/202232115106.sql
Normal file
@ -0,0 +1,5 @@
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
ALTER TABLE `toolbox_plugin` ADD COLUMN `template` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'default' AFTER `category_id`;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
@ -15,7 +15,7 @@
|
||||
<script src="/static/http.js?v={:get_version()}"></script>
|
||||
<script src="/static/common.js?v={:get_version()}"></script>
|
||||
<script src="/static/api.js?v={:get_version()}"></script>
|
||||
<link rel="stylesheet" href="/static/style.css?v={:time()}">
|
||||
<link rel="stylesheet" href="/static/style.css?v={:get_version()}">
|
||||
{block name="head"}{/block}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
20
view/index/default/template/iframe.html
Normal file
@ -0,0 +1,20 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>{$plugin.title} - {$app.title}</title>
|
||||
<link rel="icon" href="/favicon.ico"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta name="keywords" content="{$plugin.title},{$app.keywords}">
|
||||
<meta name="description" content="{$plugin.desc}">
|
||||
<meta name="author" content="Pluto" />
|
||||
<style>
|
||||
*{
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="{$plugin.config->url}" frameborder="0" width="100%" height="100%"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
34
view/index/default/template/redirect.html
Normal file
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta http-equiv="refresh" content="3;url='{$plugin.config->url}';">
|
||||
<meta charset="utf-8">
|
||||
<title>页面加载中,请稍候...</title>
|
||||
<link rel="icon" href="/favicon.ico"/>
|
||||
<meta name="keywords" content="{$plugin.title},{$app.keywords}">
|
||||
<meta name="description" content="{$plugin.desc}">
|
||||
<meta name="author" content="Pluto" />
|
||||
<script type="text/javascript">
|
||||
var msg = document.title;
|
||||
msg = "" + msg;pos = 0;
|
||||
function scrollMSG() {
|
||||
document.title = msg.substring(pos, msg.length) + msg.substring(0, pos);
|
||||
pos++;
|
||||
if (pos > msg.length) pos = 0
|
||||
window.setTimeout("scrollMSG()",200);
|
||||
}
|
||||
scrollMSG();
|
||||
</script>
|
||||
<style>body{overflow:hidden;background:#666}.container{display:flex;justify-content:center;align-items:center;height:100vh;overflow:hidden;animation-delay:1s}.item-1{width:20px;height:20px;background:#f583a1;border-radius:50%;background-color:#eed968;margin:7px;display:flex;justify-content:center;align-items:center}@keyframes scale{0%{transform:scale(1)}50%,75%{transform:scale(3.5)}78%,100%{opacity:0}}.item-1:before{content:'';width:20px;height:20px;border-radius:50%;background-color:#eed968;opacity:.7;animation:scale 2s infinite cubic-bezier(0,0,0.49,1.02);animation-delay:200ms;transition:.5s all ease;transform:scale(1)}.item-2{width:20px;height:20px;background:#f583a1;border-radius:50%;background-color:#eece68;margin:7px;display:flex;justify-content:center;align-items:center}@keyframes scale{0%{transform:scale(1)}50%,75%{transform:scale(3.5)}78%,100%{opacity:0}}.item-2:before{content:'';width:20px;height:20px;border-radius:50%;background-color:#eece68;opacity:.7;animation:scale 2s infinite cubic-bezier(0,0,0.49,1.02);animation-delay:400ms;transition:.5s all ease;transform:scale(1)}.item-3{width:20px;height:20px;background:#f583a1;border-radius:50%;background-color:#eec368;margin:7px;display:flex;justify-content:center;align-items:center}@keyframes scale{0%{transform:scale(1)}50%,75%{transform:scale(3.5)}78%,100%{opacity:0}}.item-3:before{content:'';width:20px;height:20px;border-radius:50%;background-color:#eec368;opacity:.7;animation:scale 2s infinite cubic-bezier(0,0,0.49,1.02);animation-delay:600ms;transition:.5s all ease;transform:scale(1)}.item-4{width:20px;height:20px;background:#f583a1;border-radius:50%;background-color:#eead68;margin:7px;display:flex;justify-content:center;align-items:center}@keyframes scale{0%{transform:scale(1)}50%,75%{transform:scale(3.5)}78%,100%{opacity:0}}.item-4:before{content:'';width:20px;height:20px;border-radius:50%;background-color:#eead68;opacity:.7;animation:scale 2s infinite cubic-bezier(0,0,0.49,1.02);animation-delay:800ms;transition:.5s all ease;transform:scale(1)}.item-5{width:20px;height:20px;background:#f583a1;border-radius:50%;background-color:#ee8c68;margin:7px;display:flex;justify-content:center;align-items:center}@keyframes scale{0%{transform:scale(1)}50%,75%{transform:scale(3.5)}78%,100%{opacity:0}}.item-5:before{content:'';width:20px;height:20px;border-radius:50%;background-color:#ee8c68;opacity:.7;animation:scale 2s infinite cubic-bezier(0,0,0.49,1.02);animation-delay:1000ms;transition:.5s all ease;transform:scale(1)}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="item-1"></div>
|
||||
<div class="item-2"></div>
|
||||
<div class="item-3"></div>
|
||||
<div class="item-4"></div>
|
||||
<div class="item-5"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||