Mobile UI fixes.
1
.gitignore
vendored
|
@ -7,3 +7,4 @@
|
||||||
/node_modules
|
/node_modules
|
||||||
/public/assets
|
/public/assets
|
||||||
/public/index.html
|
/public/index.html
|
||||||
|
/public/mami.webmanifest
|
||||||
|
|
77
build.js
|
@ -31,6 +31,9 @@ const buildTasks = {
|
||||||
html: [
|
html: [
|
||||||
{ source: 'mami.html', target: '/', name: 'index.html', },
|
{ source: 'mami.html', target: '/', name: 'index.html', },
|
||||||
],
|
],
|
||||||
|
webmanifest: [
|
||||||
|
{ source: 'mami.webmanifest', target: '/', name: 'mami.webmanifest', icons: '/icons' }
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,6 +191,79 @@ const htmlMinifyOptions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
console.log('Webmanifest assets...');
|
||||||
|
for(const info of buildTasks.webmanifest) {
|
||||||
|
console.log(`=> Building ${info.source}...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const body = JSON.parse(fs.readFileSync(path.join(srcDir, info.source)));
|
||||||
|
|
||||||
|
body.name = config.title;
|
||||||
|
body.short_name = config.title;
|
||||||
|
|
||||||
|
if(typeof info.icons === 'string') {
|
||||||
|
const iconsDir = path.join(pubDir, info.icons);
|
||||||
|
|
||||||
|
if(fs.existsSync(iconsDir)) {
|
||||||
|
const files = (await fs.promises.readdir(iconsDir)).sort((a, b) => a.localeCompare(b, undefined, {
|
||||||
|
numeric: true,
|
||||||
|
sensitivity: 'base',
|
||||||
|
}));
|
||||||
|
body.icons = [];
|
||||||
|
|
||||||
|
for(const file of files) {
|
||||||
|
if(!file.endsWith('.png'))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const icon = {
|
||||||
|
src: path.join(info.icons, file),
|
||||||
|
type: 'image/png',
|
||||||
|
};
|
||||||
|
|
||||||
|
if(file[0] !== 'c') {
|
||||||
|
if(file[0] === 'm')
|
||||||
|
icon.purpose = 'maskable';
|
||||||
|
else if(file[0] === 'w')
|
||||||
|
icon.purpose = 'monochrome';
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = '';
|
||||||
|
for(let i = 1; i < file.length; ++i) {
|
||||||
|
if(file[i] === 'x')
|
||||||
|
break;
|
||||||
|
res += file[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res.length > 0)
|
||||||
|
icon.sizes = `${res}x${res}`;
|
||||||
|
|
||||||
|
body.icons.push(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = JSON.stringify(body);
|
||||||
|
|
||||||
|
const name = utils.strtr(info.name, { hash: utils.shortHash(data) });
|
||||||
|
const pubName = path.join(info.target || '', name);
|
||||||
|
|
||||||
|
console.log(` Saving to ${pubName}...`);
|
||||||
|
|
||||||
|
const fullPath = path.join(pubDir, pubName);
|
||||||
|
const dirPath = path.dirname(fullPath);
|
||||||
|
if(!fs.existsSync(dirPath))
|
||||||
|
fs.mkdirSync(dirPath, { recursive: true });
|
||||||
|
|
||||||
|
fs.writeFileSync(fullPath, data);
|
||||||
|
htmlVars[info.source] = pubName;
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
console.log('HTML assets');
|
console.log('HTML assets');
|
||||||
for(const info of buildTasks.html) {
|
for(const info of buildTasks.html) {
|
||||||
|
@ -219,6 +295,7 @@ const htmlMinifyOptions = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
console.log('Cleaning up old builds...');
|
console.log('Cleaning up old builds...');
|
||||||
assproc.housekeep(pubAssetsDir);
|
assproc.housekeep(pubAssetsDir);
|
||||||
|
|
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 431 B |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 4.1 KiB |
BIN
public/icons/c114x.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
public/icons/c120x.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
public/icons/c128x.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
public/icons/c144x.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
public/icons/c152x.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
public/icons/c167x.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
public/icons/c180x.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
public/icons/c192x.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
public/icons/c256x.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
public/icons/c384x.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
public/icons/c48x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
public/icons/c512x.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
public/icons/c57x.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/icons/c60x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
public/icons/c64x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
public/icons/c72x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
public/icons/c76x.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
public/icons/c96x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
public/icons/m114x.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
public/icons/m120x.png
Normal file
After Width: | Height: | Size: 5 KiB |
BIN
public/icons/m128x.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
public/icons/m144x.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
public/icons/m152x.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
public/icons/m167x.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
public/icons/m180x.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
public/icons/m192x.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
public/icons/m256x.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
public/icons/m384x.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
public/icons/m48x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
public/icons/m512x.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
public/icons/m57x.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
public/icons/m60x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
public/icons/m64x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
public/icons/m72x.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
public/icons/m76x.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
public/icons/m96x.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
public/icons/w114x.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
public/icons/w120x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
public/icons/w128x.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
public/icons/w144x.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
public/icons/w152x.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
public/icons/w167x.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
public/icons/w180x.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
public/icons/w192x.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
public/icons/w256x.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
public/icons/w384x.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
public/icons/w48x.png
Normal file
After Width: | Height: | Size: 1,007 B |
BIN
public/icons/w512x.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
public/icons/w57x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/icons/w60x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/icons/w64x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
public/icons/w72x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
public/icons/w76x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
public/icons/w96x.png
Normal file
After Width: | Height: | Size: 2 KiB |
|
@ -1,45 +0,0 @@
|
||||||
{
|
|
||||||
"name": "Flashii Chat",
|
|
||||||
"short_name": "Flashii Chat",
|
|
||||||
"description": "Talk about trash and trash accessories.",
|
|
||||||
"start_url": "/",
|
|
||||||
"display": "standalone",
|
|
||||||
"theme_color": "#8559a5",
|
|
||||||
"background_color": "#222",
|
|
||||||
"scope": "/",
|
|
||||||
"offline_enabled": true,
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/icons/512x.png",
|
|
||||||
"sizes": "512x512"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/icons/256x.png",
|
|
||||||
"sizes": "256x256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/icons/128x.png",
|
|
||||||
"sizes": "128x128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/icons/90x.png",
|
|
||||||
"sizes": "90x90"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/icons/64x.png",
|
|
||||||
"sizes": "64x64"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/icons/48x.png",
|
|
||||||
"sizes": "48x48"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/icons/32x.png",
|
|
||||||
"sizes": "32x32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/icons/16x.png",
|
|
||||||
"sizes": "16x16"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -7,12 +7,21 @@
|
||||||
text-size-adjust: none;
|
text-size-adjust: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html {
|
||||||
|
/* what the fuck even is CSS anymore at this point */
|
||||||
|
width: 100%;
|
||||||
|
width: 100vw;
|
||||||
|
width: 100dvw;
|
||||||
|
height: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
height: 100dvh;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #000;
|
background: var(--theme-colour-main-background, #000);
|
||||||
color: #fff;
|
color: var(--theme-colour-main-colour, #fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
.chat {
|
.chat {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
margin-bottom: 5px;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
box-shadow: var(--theme-size-chat-box-shadow-x, 0) var(--theme-size-chat-box-shadow-y, 0) var(--theme-size-chat-box-shadow-blur, 0) var(--theme-size-chat-box-shadow-spread, 0) var(--theme-colour-chat-box-shadow, #000);
|
box-shadow: var(--theme-size-chat-box-shadow-x, 0) var(--theme-size-chat-box-shadow-y, 0) var(--theme-size-chat-box-shadow-blur, 0) var(--theme-size-chat-box-shadow-spread, 0) var(--theme-colour-chat-box-shadow, #000);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
text-shadow: 0 0 5px #000;
|
text-shadow: 0 0 5px #000;
|
||||||
box-shadow: inset 0 0 1em #000;
|
box-shadow: inset 0 0 1em #000;
|
||||||
|
margin: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
|
||||||
}
|
}
|
||||||
|
|
||||||
.domaintrans-body {
|
.domaintrans-body {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
.main {
|
.main {
|
||||||
flex-grow: 2;
|
flex-grow: 2;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
margin: 5px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column
|
gap: 4px;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width:768px) {
|
@media (max-width:768px) {
|
||||||
.main {
|
.main {
|
||||||
margin-right: 50px
|
margin-right: 44px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
.sidebar {
|
.sidebar {
|
||||||
margin: 5px 5px 5px 0;
|
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
font-family: Verdana, Tahoma, Geneva, Arial, Helvetica, sans-serif;
|
font-family: Verdana, Tahoma, Geneva, Arial, Helvetica, sans-serif;
|
||||||
|
@ -10,9 +9,9 @@
|
||||||
@media (max-width:768px) {
|
@media (max-width:768px) {
|
||||||
.sidebar {
|
.sidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: max(4px, env(safe-area-inset-top));
|
||||||
right: 0;
|
right: max(4px, env(safe-area-inset-right));
|
||||||
bottom: 0
|
bottom: max(4px, env(safe-area-inset-bottom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,14 @@
|
||||||
font-family: Tahoma, Geneva, Arial, Helvetica, sans-serif;
|
font-family: Tahoma, Geneva, Arial, Helvetica, sans-serif;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
background-color: var(--theme-colour-main-background, #fff);
|
background-color: var(--theme-colour-main-background, #fff);
|
||||||
color: var(--theme-colour-main-colour, #000);
|
color: var(--theme-colour-main-colour, #000);
|
||||||
scrollbar-color: var(--theme-colour-scrollbar-foreground, #000) var(--theme-colour-scrollbar-background, #fff);
|
scrollbar-color: var(--theme-colour-scrollbar-foreground, #000) var(--theme-colour-scrollbar-background, #fff);
|
||||||
padding-top: env(safe-area-inset-top);
|
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
|
||||||
padding-left: env(safe-area-inset-left);
|
|
||||||
padding-right: env(safe-area-inset-right);
|
|
||||||
accent-color: var(--theme-colour-main-accent, auto);
|
accent-color: var(--theme-colour-main-accent, auto);
|
||||||
color-scheme: var(--theme-scheme, normal);
|
color-scheme: var(--theme-scheme, normal);
|
||||||
|
padding: max(4px, env(safe-area-inset-top)) max(4px, env(safe-area-inset-right)) max(4px, env(safe-area-inset-bottom)) max(4px, env(safe-area-inset-left));
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi__main {
|
.umi__main {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: 1vh solid;
|
border: 1vh solid;
|
||||||
|
border-radius: env(safe-area-inset-top); /* this works well enough on my iphone, fuck it lol */
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
|
@ -3,9 +3,16 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<link rel="manifest" href="/manifest.json">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
|
<meta name="theme-color" content="#000000">
|
||||||
|
<link rel="manifest" href="{mami.webmanifest}">
|
||||||
|
<link rel="apple-touch-icon" sizes="120x120" href="/icons/m120x.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="152x152" href="/icons/m152x.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="167x167" href="/icons/m167x.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/icons/m180x.png">
|
||||||
<link href="/vendor/fontawesome/css/all.min.css" rel="stylesheet" type="text/css">
|
<link href="/vendor/fontawesome/css/all.min.css" rel="stylesheet" type="text/css">
|
||||||
<link href="{mami.css}" rel="stylesheet" type="text/css">
|
<link href="{mami.css}" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -47,7 +47,6 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
loadingOverlay.setMessage('Fetching credentials...');
|
loadingOverlay.setMessage('Fetching credentials...');
|
||||||
try {
|
try {
|
||||||
const auth = await MamiMisuzuAuth.update();
|
const auth = await MamiMisuzuAuth.update();
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include colour.js
|
||||||
|
|
||||||
// try to reduce these and create variations
|
// try to reduce these and create variations
|
||||||
const UmiThemes = [
|
const UmiThemes = [
|
||||||
{
|
{
|
||||||
|
@ -316,13 +318,16 @@ const UmiThemeApply = function(theme) {
|
||||||
document.body.style.setProperty(varPfx + 'scheme', theme.scheme);
|
document.body.style.setProperty(varPfx + 'scheme', theme.scheme);
|
||||||
|
|
||||||
if(theme.colours) {
|
if(theme.colours) {
|
||||||
|
if(typeof theme.colours['main-background'] === 'number') {
|
||||||
|
const themeColour = $q('meta[name="theme-color"]');
|
||||||
|
if(themeColour instanceof Element)
|
||||||
|
themeColour.content = MamiColour.hex(theme.colours['main-background']);
|
||||||
|
}
|
||||||
|
|
||||||
const coloursPfx = varPfx + 'colour-';
|
const coloursPfx = varPfx + 'colour-';
|
||||||
|
|
||||||
for(const propName in theme.colours) {
|
for(const propName in theme.colours) {
|
||||||
document.body.style.setProperty(
|
document.body.style.setProperty(coloursPfx + propName, MamiColour.hex(theme.colours[propName]));
|
||||||
coloursPfx + propName,
|
|
||||||
'#' + (theme.colours[propName].toString(16).padStart(6, '0'))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include animate.js
|
#include animate.js
|
||||||
#include rng.js
|
|
||||||
|
|
||||||
const MamiYouAreAnIdiot = function() {
|
const MamiYouAreAnIdiot = function() {
|
||||||
const html = <div class="youare">
|
const html = <div class="youare">
|
||||||
|
@ -16,7 +15,6 @@ const MamiYouAreAnIdiot = function() {
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
const rng = new MamiRNG;
|
|
||||||
let soundSrc;
|
let soundSrc;
|
||||||
|
|
||||||
const pub = {
|
const pub = {
|
||||||
|
@ -46,7 +44,7 @@ const MamiYouAreAnIdiot = function() {
|
||||||
},
|
},
|
||||||
pushOn: async views => views.push(pub, ctx => MamiAnimate({
|
pushOn: async views => views.push(pub, ctx => MamiAnimate({
|
||||||
async: true,
|
async: true,
|
||||||
duration: rng.next(1500, 15001),
|
duration: 1500,
|
||||||
easing: 'outBounce',
|
easing: 'outBounce',
|
||||||
start: () => ctx.toElem.style.top = '-100%',
|
start: () => ctx.toElem.style.top = '-100%',
|
||||||
update: t => ctx.toElem.style.top = `${-100 + (t * 100)}%`,
|
update: t => ctx.toElem.style.top = `${-100 + (t * 100)}%`,
|
||||||
|
|
10
src/mami.webmanifest
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"name": "config:title",
|
||||||
|
"short_name": "config:title",
|
||||||
|
"scope": "/",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "fullscreen",
|
||||||
|
"background_color": "#000000",
|
||||||
|
"categories": ["social"],
|
||||||
|
"icons": ["autofill"]
|
||||||
|
}
|