Compare commits
10
Commits
b060a71135
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f438590e89 | ||
|
|
08f95bfb57 | ||
|
|
b2e183e93f | ||
|
|
f7fa60ea15 | ||
|
|
831ba180f4 | ||
|
|
2fbc30ec2e | ||
|
|
f0328e86e4 | ||
|
|
fc383b34fb | ||
|
|
c5a7905b07 | ||
|
|
5ca9607377 |
+5
-3
@@ -1,3 +1,5 @@
|
|||||||
/node_modules
|
node_modules
|
||||||
package-lock.json
|
prod_dist
|
||||||
/dist
|
dev_dist
|
||||||
|
prod-dist
|
||||||
|
dev-dist
|
||||||
Vendored
+10
-16
@@ -3,30 +3,24 @@
|
|||||||
// Hover to view descriptions of existing attributes.
|
// Hover to view descriptions of existing attributes.
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"type": "node",
|
"command": "npm install",
|
||||||
|
"name": "1. Install NPM packages (first time only)",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "1. Run NPM install (first time run)",
|
"type": "node-terminal"
|
||||||
"program": "${workspaceFolder}/BuildScripts/npm-install.js"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "node",
|
"command": "npm run server",
|
||||||
|
"name": "2. Start server (w. hot)",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "2. Start webpack server (w. hot)",
|
"type": "node-terminal"
|
||||||
"program": "${workspaceFolder}/BuildScripts/webpack-server.js"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "node",
|
"command": "npm run production",
|
||||||
|
"name": "3. Build for production",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "3. Re-open localhost (if webpack server already running)",
|
"type": "node-terminal"
|
||||||
"program": "${workspaceFolder}/BuildScripts/open-localhost.js"
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "4. Publish",
|
|
||||||
"program": "${workspaceFolder}/BuildScripts/publish.js"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"typescript.tsdk": "node_modules\\typescript\\lib"
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
var exec = require('child_process').exec;
|
|
||||||
|
|
||||||
console.log("Installing NPM packages");
|
|
||||||
|
|
||||||
exec('npm install',
|
|
||||||
function (error, stdout, stderr) {
|
|
||||||
if (error !== null) {
|
|
||||||
console.error("ERROR installing NPM packages", error);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.error("Successfully installed NPM packages", stdout, stderr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
var open = require("open");
|
|
||||||
|
|
||||||
open("http://localhost:8080");
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
var npm = require("npm");
|
|
||||||
var open = require("open");
|
|
||||||
|
|
||||||
npm.load(function(err) {
|
|
||||||
npm.commands.run(['webpack-production'], function(er, data) {
|
|
||||||
// log errors or data
|
|
||||||
if (er){
|
|
||||||
console.error(er);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
console.log("Publish done!");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
npm.on('log', function(message) {
|
|
||||||
// log installation progress
|
|
||||||
console.log(message);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
var npm = require("npm");
|
|
||||||
var open = require("open");
|
|
||||||
|
|
||||||
npm.load(function(err) {
|
|
||||||
npm.commands.run(['webpack-dev-server'], function(er, data) {
|
|
||||||
// log errors or data
|
|
||||||
if (er){
|
|
||||||
console.error(er);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
open("http://localhost:8080");
|
|
||||||
npm.on('log', function(message) {
|
|
||||||
// log installation progress
|
|
||||||
console.log(message);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<app-root>
|
||||||
|
<div class="flex-horiz">
|
||||||
|
<div>col1</div>
|
||||||
|
<div>col2</div>
|
||||||
|
</div>
|
||||||
|
</app-root>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
html, body, body > * {
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-horiz {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-vert {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.flex-horiz > *, .flex-vert > * {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-horiz .flex-shrink, .flex-vert .flex-shrink {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-horiz .flex-grow, .flex-vert .flex-grow {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<div>
|
|
||||||
my app-root html here!
|
|
||||||
</div>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
html, body {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background: rgb(179, 179, 179);
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
+7
-3
@@ -1,6 +1,10 @@
|
|||||||
require("./boot.less");
|
import './app.less';
|
||||||
var bootHtml = require("./boot.html");
|
import bootHtml from './app.html';
|
||||||
var appEle = document.createElement("app-root");
|
import { AppRoot } from './elements/app-root/app-root';
|
||||||
|
|
||||||
|
window.customElements.define('app-root', AppRoot);
|
||||||
|
|
||||||
|
var appEle = document.createElement("div");
|
||||||
appEle.innerHTML = bootHtml;
|
appEle.innerHTML = bootHtml;
|
||||||
|
|
||||||
document.body.appendChild(appEle);
|
document.body.appendChild(appEle);
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export class BaseElement extends HTMLElement {
|
||||||
|
private _hasConnectedCallback: boolean = false;
|
||||||
|
connectedCallback() {
|
||||||
|
|
||||||
|
if (!this._hasConnectedCallback) {
|
||||||
|
this.onInit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._hasConnectedCallback = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onInit() { }
|
||||||
|
onUpdate() { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
app-root {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { BaseElement } from "../_base";
|
||||||
|
import './app-root.less';
|
||||||
|
|
||||||
|
export class AppRoot extends BaseElement {
|
||||||
|
onInit(): void {
|
||||||
|
console.log("APP ROOT INIT");
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdate(): void {
|
||||||
|
console.log("APP ROOT UPDATE");
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+18445
File diff suppressed because it is too large
Load Diff
+35
-24
@@ -1,33 +1,44 @@
|
|||||||
{
|
{
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"name": "new-webpack",
|
"name": "name",
|
||||||
"description": "new-webpack",
|
"description": "desc",
|
||||||
"license": "0BSD",
|
"license": "0BSD",
|
||||||
"repository": {},
|
"repository": {},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"webpack-error-details": "webpack --display-error-details",
|
"webpack": "webpack --config webpack.dev.js",
|
||||||
"webpack-development": "webpack --display-error-details --mode development",
|
"dev": "webpack --config webpack.dev.js",
|
||||||
"webpack-production": "webpack --display-error-details --mode production",
|
"server": "webpack-dev-server --port 8020 --open --config webpack.dev.js",
|
||||||
"webpack-dev-server": "webpack-dev-server"
|
"server-prod": "webpack-dev-server --port 8020 --open --config webpack.prod.js",
|
||||||
|
"production": "webpack --config webpack.prod.js"
|
||||||
},
|
},
|
||||||
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/webpack-env": "1.13.6",
|
"@types/offscreencanvas": "2019.7.3",
|
||||||
"copy-webpack-plugin": "4.5.1",
|
"@webcomponents/custom-elements": "1.6.0",
|
||||||
"css-loader": "0.28.11",
|
"@babel/core": "7.26.0",
|
||||||
"file-loader": "1.1.11",
|
"babel-loader": "9.2.1",
|
||||||
"gulp": "3.9.1",
|
"babel-plugin-transform-custom-element-classes": "0.1.0",
|
||||||
"html-loader": "0.5.5",
|
"babel-preset-env": "1.7.0",
|
||||||
"less": "3.0.2",
|
"file-loader": "6.2.0",
|
||||||
"less-loader": "4.1.0",
|
"gulp": "5.0.0",
|
||||||
"npm": "6.0.0",
|
"less": "4.2.0",
|
||||||
"open": "0.0.5",
|
"npm": "10.9.0",
|
||||||
"replace-in-file-webpack-plugin": "1.0.5",
|
"open": "10.1.0",
|
||||||
"style-loader": "0.21.0",
|
"path": "0.12.7",
|
||||||
"ts-loader": "4.2.0",
|
"webpack": "5.95.0",
|
||||||
"typescript": "2.8.3",
|
"webpack-cli": "5.1.4",
|
||||||
"webpack": "4.6.0",
|
"webpack-dev-server": "5.1.0",
|
||||||
"webpack-cli": "2.0.15",
|
"webpack-merge": "6.0.1",
|
||||||
"webpack-dev-server": "3.1.3",
|
"typescript": "5.6.3",
|
||||||
"webpack-merge": "4.1.2"
|
"node-gameloop": "0.1.4",
|
||||||
|
|
||||||
|
"replace-in-file-webpack-plugin": "1.0.6",
|
||||||
|
|
||||||
|
"copy-webpack-plugin": "12.0.2",
|
||||||
|
"html-loader": "5.1.0",
|
||||||
|
"css-loader": "7.1.2",
|
||||||
|
"less-loader": "12.2.0",
|
||||||
|
"style-loader": "4.0.0",
|
||||||
|
"ts-loader": "9.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,7 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
<title>Title</title>
|
<title>Title</title>
|
||||||
|
|
||||||
<link rel="apple-touch-icon" href="logo.png">
|
|
||||||
<link rel="apple-touch-startup-image" href='splash.png'>
|
|
||||||
|
|
||||||
<link rel="manifest" href="manifest.json?v=1">
|
<link rel="manifest" href="manifest.json?v=1">
|
||||||
|
|
||||||
<base href="/" />
|
<base href="/" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
+13
-2
@@ -2,15 +2,26 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"skipDefaultLibCheck": true,
|
"skipDefaultLibCheck": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"lib": [ "es6", "dom" ],
|
"lib": [ "es6", "dom" ],
|
||||||
"types": [ "webpack-env" ],
|
"types": [ ],
|
||||||
|
"baseUrl": "./node_modules",
|
||||||
"allowJs": true
|
"allowJs": true
|
||||||
},
|
},
|
||||||
"exclude": [ "bin", "node_modules" ],
|
"exclude": [
|
||||||
|
"dev-dist",
|
||||||
|
"prod-dist",
|
||||||
|
"bin",
|
||||||
|
"BuildScripts",
|
||||||
|
"node_modules",
|
||||||
|
"webpack.common.js",
|
||||||
|
"webpack.dev.js",
|
||||||
|
"webpack.prod.js"
|
||||||
|
],
|
||||||
"atom": { "rewriteTsconfig": false }
|
"atom": { "rewriteTsconfig": false }
|
||||||
}
|
}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
declare module '*.html' {
|
||||||
|
const content: string;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.png';
|
||||||
|
declare module '*.jpg';
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
const path = require('path');
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
'main': path.resolve(__dirname, 'App', 'boot.ts')
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".ts", ".js", ".json"]
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
//ts to js
|
||||||
|
test: /\.ts$/,
|
||||||
|
use: 'ts-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//html to js
|
||||||
|
test: /\.html$/,
|
||||||
|
use: 'html-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//css to js to inline style append
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ['style-loader', 'css-loader']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//less to css to js to inline style append
|
||||||
|
test: /\.less$/,
|
||||||
|
use: ['style-loader', 'css-loader', 'less-loader']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
const webpack = require('webpack');
|
|
||||||
const merge = require('webpack-merge');
|
|
||||||
const path = require('path');
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
||||||
const ReplaceInFileWebpackPlugin = require('replace-in-file-webpack-plugin');
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = (env, argv) => {
|
|
||||||
|
|
||||||
var isDevServer = argv.mode === undefined;
|
|
||||||
|
|
||||||
if (isDevServer && __dirname.indexOf(" ") !== -1) {
|
|
||||||
throw new Error("Space in __dirname not allowed: " + __dirname);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sharedSettings = {
|
|
||||||
entry: {
|
|
||||||
'main': path.resolve(__dirname, 'App', 'boot.ts')
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: [".ts", ".js", ".json"]
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
//ts to js
|
|
||||||
test: /\.ts$/,
|
|
||||||
use: 'ts-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
//html to js
|
|
||||||
test: /\.html$/,
|
|
||||||
use: 'html-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
//css to js to inline style append
|
|
||||||
test: /\.css$/,
|
|
||||||
use: ['style-loader', 'css-loader']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
//less to css to js to inline style append
|
|
||||||
test: /\.less$/,
|
|
||||||
use: ['style-loader', 'css-loader', 'less-loader']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const developmentSettings = {
|
|
||||||
mode: 'development',
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist"),
|
|
||||||
publicPath: "/",
|
|
||||||
filename: 'main.js'
|
|
||||||
},
|
|
||||||
devServer: {
|
|
||||||
contentBase: './dist',
|
|
||||||
historyApiFallback: true
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new CopyWebpackPlugin([
|
|
||||||
{
|
|
||||||
from: path.resolve(__dirname, '*.html'),
|
|
||||||
to: path.resolve(__dirname, 'dist', '[name].[ext]')
|
|
||||||
}
|
|
||||||
])
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
const productionSettings = {
|
|
||||||
mode: "production",
|
|
||||||
plugins: [
|
|
||||||
new CopyWebpackPlugin([
|
|
||||||
{
|
|
||||||
from: path.resolve(__dirname, '*.html'),
|
|
||||||
to: path.resolve(__dirname, 'dist', '[name].[ext]')
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
new ReplaceInFileWebpackPlugin(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
dir: path.join(__dirname, 'dist'),
|
|
||||||
test: /\.html$/,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
search: /((\?|\&)v\=)(.+?)(?=\"|\'|\&)/ig,
|
|
||||||
replace: (match) => {
|
|
||||||
return match.toString().substr(0, 3) +
|
|
||||||
+new Date();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
//to merge sharedSettings
|
|
||||||
var dev = Object.assign({}, sharedSettings, developmentSettings);
|
|
||||||
var prod = Object.assign({}, sharedSettings, productionSettings);
|
|
||||||
|
|
||||||
|
|
||||||
//return dev or prod to webpack depending on --mode config (webpack-dev-server: argv.mode = undefined)
|
|
||||||
return argv.mode === "development" || argv.mode === undefined ? dev : prod;
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const copyPlugin = require('copy-webpack-plugin');
|
||||||
|
const common = require('./webpack.common.js');
|
||||||
|
|
||||||
|
const devFolderName = "dev-dist";
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: 'development',
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, devFolderName),
|
||||||
|
publicPath: "/",
|
||||||
|
filename: 'main.js'
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
static: {
|
||||||
|
directory: path.join(__dirname, devFolderName),
|
||||||
|
},
|
||||||
|
historyApiFallback: true
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new copyPlugin(
|
||||||
|
{
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
from: path.resolve(__dirname, 'static'),
|
||||||
|
to: path.resolve(__dirname, devFolderName, '[name][ext]')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
});
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const common = require('./webpack.common.js');
|
||||||
|
const path = require('path');
|
||||||
|
const ReplaceInFileWebpackPlugin = require('replace-in-file-webpack-plugin');
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
|
const prodFolderName = "prod-dist";
|
||||||
|
|
||||||
|
const replaceVersionInHtmlOption = {
|
||||||
|
//set ?v= with new date in html files for production
|
||||||
|
dir: path.join(__dirname, prodFolderName),
|
||||||
|
test: /\.html$/,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
search: /((\?|\&)v\=)(.+?)(?=\"|\'|\&)/ig,
|
||||||
|
replace: (match) => {
|
||||||
|
return match.toString().substr(0, 3) +
|
||||||
|
+new Date();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: "production",
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, prodFolderName),
|
||||||
|
publicPath: "/",
|
||||||
|
filename: 'main.js'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CopyWebpackPlugin(
|
||||||
|
{
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
from: path.resolve(__dirname, 'static'),
|
||||||
|
to: path.resolve(__dirname, prodFolderName, '[name][ext]')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
new ReplaceInFileWebpackPlugin(
|
||||||
|
[
|
||||||
|
replaceVersionInHtmlOption
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user