mirror of
https://github.com/tabler/tabler.git
synced 2025-12-22 01:44:25 +04:00
Config improvements (#2472)
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { appFilters } from "../shared/e11ty/filters.mjs"
|
import { appFilters } from "../shared/e11ty/filters.mjs"
|
||||||
import { appData } from "../shared/e11ty/data.mjs";
|
import { appData } from "../shared/e11ty/data.mjs";
|
||||||
|
import { appConfig } from "../shared/e11ty/config.mjs";
|
||||||
import { readFileSync, existsSync } from 'node:fs';
|
import { readFileSync, existsSync } from 'node:fs';
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import { join, dirname } from 'node:path';
|
import { join, dirname } from 'node:path';
|
||||||
@@ -13,6 +14,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
|||||||
export default function (eleventyConfig) {
|
export default function (eleventyConfig) {
|
||||||
const environment = process.env.NODE_ENV || "production";
|
const environment = process.env.NODE_ENV || "production";
|
||||||
|
|
||||||
|
appConfig(eleventyConfig);
|
||||||
appFilters(eleventyConfig);
|
appFilters(eleventyConfig);
|
||||||
appData(eleventyConfig);
|
appData(eleventyConfig);
|
||||||
|
|
||||||
@@ -29,11 +31,6 @@ export default function (eleventyConfig) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
eleventyConfig.setInputDirectory("content");
|
eleventyConfig.setInputDirectory("content");
|
||||||
eleventyConfig.setOutputDirectory("dist");
|
|
||||||
|
|
||||||
eleventyConfig.setLayoutsDirectory("../../shared/layouts");
|
|
||||||
eleventyConfig.setIncludesDirectory("../../shared/includes");
|
|
||||||
eleventyConfig.setDataDirectory("../../shared/data");
|
|
||||||
|
|
||||||
eleventyConfig.amendLibrary('md', () => { });
|
eleventyConfig.amendLibrary('md', () => { });
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@11ty/eleventy": "^3.1.2",
|
"@11ty/eleventy": "3.1.0",
|
||||||
"@docsearch/css": "^3.9.0",
|
"@docsearch/css": "^3.9.0",
|
||||||
"@docsearch/js": "^3.9.0",
|
"@docsearch/js": "^3.9.0",
|
||||||
"flat-cache": "^6.1.11",
|
"flat-cache": "^6.1.11",
|
||||||
|
|||||||
20
pnpm-lock.yaml
generated
20
pnpm-lock.yaml
generated
@@ -183,8 +183,8 @@ importers:
|
|||||||
version: link:../core
|
version: link:../core
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@11ty/eleventy':
|
'@11ty/eleventy':
|
||||||
specifier: ^3.1.2
|
specifier: 3.1.0
|
||||||
version: 3.1.2
|
version: 3.1.0
|
||||||
'@docsearch/css':
|
'@docsearch/css':
|
||||||
specifier: ^3.9.0
|
specifier: ^3.9.0
|
||||||
version: 3.9.0
|
version: 3.9.0
|
||||||
@@ -208,8 +208,8 @@ importers:
|
|||||||
version: 3.34.1
|
version: 3.34.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@11ty/eleventy':
|
'@11ty/eleventy':
|
||||||
specifier: ^3.1.1
|
specifier: 3.1.0
|
||||||
version: 3.1.2
|
version: 3.1.0
|
||||||
imageoptim-cli:
|
imageoptim-cli:
|
||||||
specifier: ^3.1.9
|
specifier: ^3.1.9
|
||||||
version: 3.1.9
|
version: 3.1.9
|
||||||
@@ -238,8 +238,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-6QE+duqSQ0GY9rENXYb4iPR4AYGdrFpqnmi59tFp9VrleOl0QSh8VlBr2yd6dlhkdtj7904poZW5PvGr9cMiJQ==}
|
resolution: {integrity: sha512-6QE+duqSQ0GY9rENXYb4iPR4AYGdrFpqnmi59tFp9VrleOl0QSh8VlBr2yd6dlhkdtj7904poZW5PvGr9cMiJQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@11ty/eleventy@3.1.2':
|
'@11ty/eleventy@3.1.0':
|
||||||
resolution: {integrity: sha512-IcsDlbXnBf8cHzbM1YBv3JcTyLB35EK88QexmVyFdVJVgUU6bh9g687rpxryJirHzo06PuwnYaEEdVZQfIgRGg==}
|
resolution: {integrity: sha512-yR8zE+i5GKXTlR4I6Aj8dywI7f2/6uGhJPwgbH4vgh+XcZQ9zba9UMS/1Lyvkbl3UySRSAmlzeYiXi1ypV6oZg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -3169,7 +3169,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@11ty/eleventy-utils': 2.0.7
|
'@11ty/eleventy-utils': 2.0.7
|
||||||
chokidar: 3.6.0
|
chokidar: 3.6.0
|
||||||
debug: 4.4.0(supports-color@5.5.0)
|
debug: 4.4.1
|
||||||
finalhandler: 1.3.1
|
finalhandler: 1.3.1
|
||||||
mime: 3.0.0
|
mime: 3.0.0
|
||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
@@ -3187,7 +3187,7 @@ snapshots:
|
|||||||
'@11ty/eleventy-plugin-bundle@3.0.6(posthtml@0.16.6)':
|
'@11ty/eleventy-plugin-bundle@3.0.6(posthtml@0.16.6)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@11ty/eleventy-utils': 2.0.7
|
'@11ty/eleventy-utils': 2.0.7
|
||||||
debug: 4.4.0(supports-color@5.5.0)
|
debug: 4.4.1
|
||||||
posthtml-match-helper: 2.0.3(posthtml@0.16.6)
|
posthtml-match-helper: 2.0.3(posthtml@0.16.6)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- posthtml
|
- posthtml
|
||||||
@@ -3195,7 +3195,7 @@ snapshots:
|
|||||||
|
|
||||||
'@11ty/eleventy-utils@2.0.7': {}
|
'@11ty/eleventy-utils@2.0.7': {}
|
||||||
|
|
||||||
'@11ty/eleventy@3.1.2':
|
'@11ty/eleventy@3.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@11ty/dependency-tree': 4.0.0
|
'@11ty/dependency-tree': 4.0.0
|
||||||
'@11ty/dependency-tree-esm': 2.0.0
|
'@11ty/dependency-tree-esm': 2.0.0
|
||||||
@@ -5747,7 +5747,7 @@ snapshots:
|
|||||||
|
|
||||||
send@1.2.0:
|
send@1.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.0(supports-color@5.5.0)
|
debug: 4.4.1
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
etag: 1.8.1
|
etag: 1.8.1
|
||||||
|
|||||||
@@ -4,21 +4,17 @@ import { join } from 'node:path';
|
|||||||
import { sync } from 'glob';
|
import { sync } from 'glob';
|
||||||
import { appFilters } from "../shared/e11ty/filters.mjs";
|
import { appFilters } from "../shared/e11ty/filters.mjs";
|
||||||
import { appData } from "../shared/e11ty/data.mjs"
|
import { appData } from "../shared/e11ty/data.mjs"
|
||||||
|
import { appConfig } from "../shared/e11ty/config.mjs"
|
||||||
|
|
||||||
/** @type {import('@11ty/eleventy').LocalConfig} */
|
/** @type {import('@11ty/eleventy').LocalConfig} */
|
||||||
export default function (eleventyConfig) {
|
export default function (eleventyConfig) {
|
||||||
const environment = process.env.NODE_ENV || "production";
|
const environment = process.env.NODE_ENV || "production";
|
||||||
|
const currentDir = process.cwd();
|
||||||
|
|
||||||
|
appConfig(eleventyConfig);
|
||||||
appFilters(eleventyConfig);
|
appFilters(eleventyConfig);
|
||||||
appData(eleventyConfig);
|
appData(eleventyConfig);
|
||||||
|
|
||||||
eleventyConfig.setInputDirectory("pages");
|
|
||||||
eleventyConfig.setOutputDirectory("dist");
|
|
||||||
|
|
||||||
eleventyConfig.setLayoutsDirectory("../../shared/layouts");
|
|
||||||
eleventyConfig.setIncludesDirectory("../../shared/includes");
|
|
||||||
eleventyConfig.setDataDirectory("../../shared/data");
|
|
||||||
|
|
||||||
eleventyConfig.addPassthroughCopy({
|
eleventyConfig.addPassthroughCopy({
|
||||||
"node_modules/@tabler/core/dist": "dist",
|
"node_modules/@tabler/core/dist": "dist",
|
||||||
"pages/favicon.ico": "favicon.ico",
|
"pages/favicon.ico": "favicon.ico",
|
||||||
@@ -47,169 +43,6 @@ export default function (eleventyConfig) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters
|
|
||||||
*/
|
|
||||||
eleventyConfig.addFilter("miliseconds_to_minutes", function (value) {
|
|
||||||
// Raturn 3:45 time format
|
|
||||||
const minutes = Math.floor(value / 60000);
|
|
||||||
const seconds = ((value % 60000) / 1000).toFixed(0);
|
|
||||||
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("relative", (page) => {
|
|
||||||
const segments = (page.url || '').replace(/^\//).split('/');
|
|
||||||
if (segments.length === 1) {
|
|
||||||
return '.';
|
|
||||||
} else {
|
|
||||||
return '../'.repeat(segments.length - 1).slice(0, -1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("contains", (items, item) => {
|
|
||||||
return items && Array.isArray(items) && items.includes(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("concat_objects", function (object, object2) {
|
|
||||||
if (
|
|
||||||
object &&
|
|
||||||
object2 &&
|
|
||||||
typeof object === 'object' &&
|
|
||||||
typeof object2 === 'object' &&
|
|
||||||
!Array.isArray(object) &&
|
|
||||||
!Array.isArray(object2)
|
|
||||||
) {
|
|
||||||
return { ...object, ...object2 };
|
|
||||||
}
|
|
||||||
return object;
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("replace_regex", function (input, regStr, replStr) {
|
|
||||||
const regex = new RegExp(regStr, 'gm');
|
|
||||||
return input.replace(regex, replStr);
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("timestamp_to_date", function (timestamp) {
|
|
||||||
const date = new Date(timestamp * 1000); // Convert timestamp to milliseconds
|
|
||||||
return date.toISOString().split('T')[0]; // Extract the date in 'YYYY-MM-DD' format
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("split_to_n", function (arr, n) {
|
|
||||||
const chunkSize = Math.round(arr.length / n);
|
|
||||||
const result = [];
|
|
||||||
for (let i = 0; i < arr.length; i += chunkSize) {
|
|
||||||
result.push(arr.slice(i, i + chunkSize));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
})
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("format_number", function (value) {
|
|
||||||
return value.toString()
|
|
||||||
.split('')
|
|
||||||
.reverse()
|
|
||||||
.reduce((acc, char, index) => {
|
|
||||||
if (index > 0 && index % 3 === 0) {
|
|
||||||
acc.push(',');
|
|
||||||
}
|
|
||||||
acc.push(char);
|
|
||||||
return acc;
|
|
||||||
}, [])
|
|
||||||
.reverse()
|
|
||||||
.join('');
|
|
||||||
});
|
|
||||||
|
|
||||||
function randomNumber(x, min = 0, max = 100, round = 0) {
|
|
||||||
let value = ((x * x * Math.PI * Math.E * (max + 1) * (Math.sin(x) / Math.cos(x * x))) % (max + 1 - min)) + min;
|
|
||||||
|
|
||||||
value = value > max ? max : value;
|
|
||||||
value = value < min ? min : value;
|
|
||||||
|
|
||||||
if (round !== 0) {
|
|
||||||
value = parseFloat(value.toFixed(round));
|
|
||||||
} else {
|
|
||||||
value = Math.floor(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("random_date_ago", function (x, daysAgo = 100) {
|
|
||||||
const today = new Date();
|
|
||||||
const randomDaysAgo = randomNumber(x, 0, daysAgo);
|
|
||||||
today.setDate(today.getDate() - randomDaysAgo);
|
|
||||||
return today;
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("random_date", function (x, startDate = null, endDate = null) {
|
|
||||||
const start = new Date(startDate ? startDate : '2024-01-01').getTime() / 1000;
|
|
||||||
const end = new Date(endDate ? endDate : '2024-12-30').getTime() / 1000;
|
|
||||||
|
|
||||||
const randomTimestamp = randomNumber(x, start, end);
|
|
||||||
return new Date(randomTimestamp * 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("random_item", function (x, items) {
|
|
||||||
const index = randomNumber(x, 0, items.length - 1);
|
|
||||||
return items[index];
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("random_number", randomNumber);
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("first_letters", function capitalizeFirstLetter(string) {
|
|
||||||
return string.split(' ').map(word => word.charAt(0)).join('');
|
|
||||||
})
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("uc_first", function capitalizeFirstLetter(string) {
|
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
||||||
})
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("size", function (elem) {
|
|
||||||
if (elem instanceof Object) {
|
|
||||||
return Object.keys(elem).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return elem.length;
|
|
||||||
})
|
|
||||||
|
|
||||||
eleventyConfig.addFilter("first", function (elem) {
|
|
||||||
if (elem instanceof Object) {
|
|
||||||
return elem[Object.keys(elem)[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return elem[0];
|
|
||||||
})
|
|
||||||
|
|
||||||
// time ago from today
|
|
||||||
eleventyConfig.addFilter("timeago", function (date) {
|
|
||||||
const seconds = Math.floor((new Date() - date) / 1000);
|
|
||||||
|
|
||||||
let interval = Math.floor(seconds / 31536000);
|
|
||||||
|
|
||||||
if (interval > 1) {
|
|
||||||
return interval + " years ago";
|
|
||||||
}
|
|
||||||
interval = Math.floor(seconds / 2592000);
|
|
||||||
if (interval > 1) {
|
|
||||||
return interval + " months ago";
|
|
||||||
}
|
|
||||||
interval = Math.floor(seconds / 86400);
|
|
||||||
if (interval > 1) {
|
|
||||||
return interval + " days ago";
|
|
||||||
}
|
|
||||||
interval = Math.floor(seconds / 3600);
|
|
||||||
if (interval > 1) {
|
|
||||||
return interval + " hours ago";
|
|
||||||
}
|
|
||||||
interval = Math.floor(seconds / 60);
|
|
||||||
if (interval > 1) {
|
|
||||||
return interval + " minutes ago";
|
|
||||||
}
|
|
||||||
if (seconds > 0) {
|
|
||||||
return Math.floor(seconds) + " seconds ago";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "now";
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcodes
|
* Shortcodes
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"build": "pnpm run clean && pnpm run css && pnpm run js && pnpm run html",
|
"build": "pnpm run clean && pnpm run css && pnpm run js && pnpm run html",
|
||||||
"dev": "pnpm run clean && pnpm run watch",
|
"dev": "pnpm run clean && pnpm run watch",
|
||||||
"watch": "concurrently \"pnpm run watch-html\" \"pnpm run watch-css\" \"pnpm run watch-js\"",
|
"watch": "concurrently \"pnpm run watch-html\" \"pnpm run watch-css\" \"pnpm run watch-js\"",
|
||||||
"watch-html": "cross-env NODE_ENV=development eleventy --serve --port=3000 --incremental",
|
"watch-html": "cross-env NODE_ENV=development eleventy --serve --port=3000 --watch --incremental",
|
||||||
"watch-js": "nodemon --watch js/ --ext js --exec \"pnpm run js\"",
|
"watch-js": "nodemon --watch js/ --ext js --exec \"pnpm run js\"",
|
||||||
"watch-css": "nodemon --watch scss/ --ext scss --exec \"pnpm run css\"",
|
"watch-css": "nodemon --watch scss/ --ext scss --exec \"pnpm run css\"",
|
||||||
"css": "pnpm run css-compile && pnpm run css-prefix && pnpm run css-minify",
|
"css": "pnpm run css-compile && pnpm run css-prefix && pnpm run css-minify",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"zip": "mkdir -p packages-zip && zip -r packages-zip/tabler-$(node -p \"require('./package.json').version\").zip demo/*"
|
"zip": "mkdir -p packages-zip && zip -r packages-zip/tabler-$(node -p \"require('./package.json').version\").zip demo/*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@11ty/eleventy": "^3.1.1",
|
"@11ty/eleventy": "3.1.0",
|
||||||
"imageoptim-cli": "^3.1.9",
|
"imageoptim-cli": "^3.1.9",
|
||||||
"request": "^2.88.2"
|
"request": "^2.88.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
page-menu: home
|
page-menu: home
|
||||||
layout: homepage
|
layout: homepage
|
||||||
|
permalink: index.html
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
23
shared/e11ty/config.mjs
Normal file
23
shared/e11ty/config.mjs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export function appConfig(eleventyConfig) {
|
||||||
|
eleventyConfig.setOutputDirectory("dist");
|
||||||
|
eleventyConfig.setInputDirectory("pages");
|
||||||
|
|
||||||
|
eleventyConfig.setLayoutsDirectory("../../shared/layouts");
|
||||||
|
eleventyConfig.setIncludesDirectory("../../shared/includes");
|
||||||
|
eleventyConfig.setDataDirectory("../../shared/data");
|
||||||
|
|
||||||
|
eleventyConfig.addWatchTarget("../shared/**/*.html");
|
||||||
|
eleventyConfig.addWatchTarget("./pages/**/*.html");
|
||||||
|
|
||||||
|
console.log('ELEVENTY CONFIG additionalWatchTargets', eleventyConfig.directoryAssignments);
|
||||||
|
|
||||||
|
eleventyConfig.setLiquidOptions({
|
||||||
|
timezoneOffset: 0,
|
||||||
|
jekyllInclude: true,
|
||||||
|
dynamicPartials: true,
|
||||||
|
jekyllWhere: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
eleventyConfig.setServerPassthroughCopyBehavior("passthrough");
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,20 +1,4 @@
|
|||||||
export function appFilters(eleventyConfig) {
|
export function appFilters(eleventyConfig) {
|
||||||
/**
|
|
||||||
* Server
|
|
||||||
*/
|
|
||||||
if (process.env.ELEVENTY_RUN_MODE === "serve") {
|
|
||||||
eleventyConfig.setServerPassthroughCopyBehavior("passthrough");
|
|
||||||
}
|
|
||||||
|
|
||||||
eleventyConfig.setLiquidOptions({
|
|
||||||
timezoneOffset: 0,
|
|
||||||
jekyllInclude: true,
|
|
||||||
dynamicPartials: true,
|
|
||||||
jekyllWhere: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
eleventyConfig.setServerPassthroughCopyBehavior("passthrough");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters
|
* Filters
|
||||||
*/
|
*/
|
||||||
@@ -135,7 +119,7 @@ export function appFilters(eleventyConfig) {
|
|||||||
eleventyConfig.addFilter("random_number", randomNumber);
|
eleventyConfig.addFilter("random_number", randomNumber);
|
||||||
|
|
||||||
eleventyConfig.addFilter("first_letters", function capitalizeFirstLetter(string) {
|
eleventyConfig.addFilter("first_letters", function capitalizeFirstLetter(string) {
|
||||||
return string.split(' ').map(word => word.charAt(0)).join('');
|
return (string || '').split(' ').map(word => word.charAt(0)).join('');
|
||||||
})
|
})
|
||||||
|
|
||||||
eleventyConfig.addFilter("uc_first", function capitalizeFirstLetter(string) {
|
eleventyConfig.addFilter("uc_first", function capitalizeFirstLetter(string) {
|
||||||
@@ -147,7 +131,11 @@ export function appFilters(eleventyConfig) {
|
|||||||
return Object.keys(elem).length;
|
return Object.keys(elem).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return elem.length;
|
if (elem) {
|
||||||
|
return elem.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
})
|
})
|
||||||
|
|
||||||
eleventyConfig.addFilter("first", function (elem) {
|
eleventyConfig.addFilter("first", function (elem) {
|
||||||
@@ -155,7 +143,7 @@ export function appFilters(eleventyConfig) {
|
|||||||
return elem[Object.keys(elem)[0]];
|
return elem[Object.keys(elem)[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return elem[0];
|
return elem ? elem[0] : null;
|
||||||
})
|
})
|
||||||
|
|
||||||
// Convert a URL path to an absolute URL
|
// Convert a URL path to an absolute URL
|
||||||
|
|||||||
Reference in New Issue
Block a user