Accessibility fixes
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"semi": false,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"trailingComma": "none",
|
"trailingComma": "all",
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": "*.yml",
|
"files": "*.yml",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import prettierConfig from 'eslint-config-prettier/flat'
|
import prettierConfig from 'eslint-config-prettier/flat';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
@@ -9,12 +9,12 @@ export default [
|
|||||||
globals: {
|
globals: {
|
||||||
window: 'readonly',
|
window: 'readonly',
|
||||||
document: 'readonly',
|
document: 'readonly',
|
||||||
dataLayer: 'writable'
|
dataLayer: 'writable',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }]
|
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
||||||
}
|
|
||||||
},
|
},
|
||||||
prettierConfig
|
},
|
||||||
]
|
prettierConfig,
|
||||||
|
];
|
||||||
|
|||||||
@@ -8,71 +8,71 @@ import {
|
|||||||
readFileSync,
|
readFileSync,
|
||||||
writeFileSync,
|
writeFileSync,
|
||||||
cpSync,
|
cpSync,
|
||||||
readdirSync
|
readdirSync,
|
||||||
} from 'fs'
|
} from 'fs';
|
||||||
import { join, dirname, extname } from 'path'
|
import { join, dirname, extname } from 'path';
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url';
|
||||||
import Beasties from 'beasties'
|
import Beasties from 'beasties';
|
||||||
import { minify as minifyJs } from 'terser'
|
import { minify as minifyJs } from 'terser';
|
||||||
import CleanCSS from 'clean-css'
|
import CleanCSS from 'clean-css';
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
const root = join(__dirname, '..')
|
const root = join(__dirname, '..');
|
||||||
const srcDir = join(root, 'src')
|
const srcDir = join(root, 'src');
|
||||||
const distDir = join(root, 'dist')
|
const distDir = join(root, 'dist');
|
||||||
|
|
||||||
function getFiles(dir, files = []) {
|
function getFiles(dir, files = []) {
|
||||||
const entries = readdirSync(dir, { withFileTypes: true })
|
const entries = readdirSync(dir, { withFileTypes: true });
|
||||||
for (const e of entries) {
|
for (const e of entries) {
|
||||||
const full = join(dir, e.name)
|
const full = join(dir, e.name);
|
||||||
if (e.isDirectory()) getFiles(full, files)
|
if (e.isDirectory()) getFiles(full, files);
|
||||||
else files.push(full)
|
else files.push(full);
|
||||||
}
|
}
|
||||||
return files
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
// 1. Clean and copy src → dist
|
// 1. Clean and copy src → dist
|
||||||
rmSync(distDir, { recursive: true, force: true })
|
rmSync(distDir, { recursive: true, force: true });
|
||||||
mkdirSync(distDir, { recursive: true })
|
mkdirSync(distDir, { recursive: true });
|
||||||
cpSync(srcDir, distDir, { recursive: true })
|
cpSync(srcDir, distDir, { recursive: true });
|
||||||
|
|
||||||
const distFiles = getFiles(distDir)
|
const distFiles = getFiles(distDir);
|
||||||
|
|
||||||
// 2. Minify JS
|
// 2. Minify JS
|
||||||
const jsFiles = distFiles.filter((f) => extname(f) === '.js')
|
const jsFiles = distFiles.filter((f) => extname(f) === '.js');
|
||||||
for (const f of jsFiles) {
|
for (const f of jsFiles) {
|
||||||
const code = readFileSync(f, 'utf8')
|
const code = readFileSync(f, 'utf8');
|
||||||
const result = await minifyJs(code, { format: { comments: false } })
|
const result = await minifyJs(code, { format: { comments: false } });
|
||||||
if (result.code) writeFileSync(f, result.code)
|
if (result.code) writeFileSync(f, result.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Minify CSS
|
// 3. Minify CSS
|
||||||
const cleanCss = new CleanCSS({ level: 2 })
|
const cleanCss = new CleanCSS({ level: 2 });
|
||||||
const cssFiles = distFiles.filter((f) => extname(f) === '.css')
|
const cssFiles = distFiles.filter((f) => extname(f) === '.css');
|
||||||
for (const f of cssFiles) {
|
for (const f of cssFiles) {
|
||||||
const code = readFileSync(f, 'utf8')
|
const code = readFileSync(f, 'utf8');
|
||||||
const result = cleanCss.minify(code)
|
const result = cleanCss.minify(code);
|
||||||
if (!result.errors.length) writeFileSync(f, result.styles)
|
if (!result.errors.length) writeFileSync(f, result.styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Inline critical CSS with Beasties for all HTML files (no browser; works in CI)
|
// 4. Inline critical CSS with Beasties for all HTML files (no browser; works in CI)
|
||||||
const htmlFiles = distFiles.filter((f) => extname(f) === '.html')
|
const htmlFiles = distFiles.filter((f) => extname(f) === '.html');
|
||||||
const beasties = new Beasties({
|
const beasties = new Beasties({
|
||||||
path: distDir,
|
path: distDir,
|
||||||
preload: 'default',
|
preload: 'default',
|
||||||
logLevel: 'warn'
|
logLevel: 'warn',
|
||||||
})
|
});
|
||||||
for (const htmlFile of htmlFiles) {
|
for (const htmlFile of htmlFiles) {
|
||||||
const html = readFileSync(htmlFile, 'utf8')
|
const html = readFileSync(htmlFile, 'utf8');
|
||||||
const inlined = await beasties.process(html)
|
const inlined = await beasties.process(html);
|
||||||
writeFileSync(htmlFile, inlined)
|
writeFileSync(htmlFile, inlined);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Build complete: dist/')
|
console.log('Build complete: dist/');
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((err) => {
|
main().catch((err) => {
|
||||||
console.error(err)
|
console.error(err);
|
||||||
process.exit(1)
|
process.exit(1);
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -44,9 +44,53 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
color: #374151;
|
||||||
|
font-size: 0.94em;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
padding: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.footer {
|
||||||
|
color: #aab2bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-link {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
background: var(--accent);
|
||||||
|
color: var(--button-text);
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
z-index: 100;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-link:focus {
|
||||||
|
transform: translateY(0);
|
||||||
|
outline: 2px solid var(--accent-light);
|
||||||
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -194,9 +238,10 @@ td:first-child {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tip colors chosen for WCAG 2.2 AAA (≥7:1 contrast) */
|
||||||
.tip {
|
.tip {
|
||||||
background: #eef2ff;
|
background: #eef2ff;
|
||||||
color: var(--accent-light);
|
color: #3730a3;
|
||||||
border-radius: 0.7em;
|
border-radius: 0.7em;
|
||||||
font-size: 0.98em;
|
font-size: 0.98em;
|
||||||
padding: 0.48em 0.8em;
|
padding: 0.48em 0.8em;
|
||||||
@@ -207,7 +252,7 @@ td:first-child {
|
|||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
.tip {
|
.tip {
|
||||||
background: #232555;
|
background: #232555;
|
||||||
color: #a5b4fc;
|
color: #c7d2fe;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,14 +340,6 @@ td:first-child {
|
|||||||
color: var(--faq-a);
|
color: var(--faq-a);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
|
||||||
margin-top: 2.5em;
|
|
||||||
text-align: center;
|
|
||||||
color: #bbb;
|
|
||||||
font-size: 0.94em;
|
|
||||||
letter-spacing: 0.01em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (width <= 600px) {
|
@media (width <= 600px) {
|
||||||
.container {
|
.container {
|
||||||
padding: 1.1rem 0.5rem 1rem;
|
padding: 1.1rem 0.5rem 1rem;
|
||||||
|
|||||||
37
src/assets/js/accordion.js
Normal file
37
src/assets/js/accordion.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Native accessible accordion
|
||||||
|
document.querySelectorAll('.accordion-trigger').forEach((btn) => {
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
const section = btn.closest('.accordion-section');
|
||||||
|
const expanded = btn.getAttribute('aria-expanded') === 'true';
|
||||||
|
document.querySelectorAll('.accordion-section').forEach((s) => {
|
||||||
|
if (s === section) {
|
||||||
|
s.classList.toggle('open', !expanded);
|
||||||
|
btn.setAttribute('aria-expanded', String(!expanded));
|
||||||
|
const content = btn.nextElementSibling;
|
||||||
|
content.style.maxHeight = !expanded
|
||||||
|
? content.scrollHeight + 40 + 'px'
|
||||||
|
: '0px';
|
||||||
|
} else {
|
||||||
|
s.classList.remove('open');
|
||||||
|
s.querySelector('.accordion-trigger').setAttribute(
|
||||||
|
'aria-expanded',
|
||||||
|
'false',
|
||||||
|
);
|
||||||
|
s.querySelector('.accordion-content').style.maxHeight = '0px';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Allow arrow navigation
|
||||||
|
btn.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
||||||
|
const triggers = Array.from(
|
||||||
|
document.querySelectorAll('.accordion-trigger'),
|
||||||
|
);
|
||||||
|
let idx = triggers.indexOf(e.target);
|
||||||
|
if (e.key === 'ArrowDown') idx = (idx + 1) % triggers.length;
|
||||||
|
else idx = (idx - 1 + triggers.length) % triggers.length;
|
||||||
|
triggers[idx].focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
4
src/assets/js/current-year.js
Normal file
4
src/assets/js/current-year.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
(function () {
|
||||||
|
const year = new Date().getFullYear();
|
||||||
|
document.getElementById('current-year').textContent = `–${year}`;
|
||||||
|
})();
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
;(function () {
|
(function () {
|
||||||
var script = document.currentScript
|
var script = document.currentScript;
|
||||||
var id = script && script.getAttribute('data-ga-id')
|
var id = script && script.getAttribute('data-ga-id');
|
||||||
if (!id) return
|
if (!id) return;
|
||||||
window.dataLayer = window.dataLayer || []
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag() {
|
function gtag() {
|
||||||
window.dataLayer.push(arguments)
|
window.dataLayer.push(arguments);
|
||||||
}
|
}
|
||||||
gtag('js', new Date())
|
gtag('js', new Date());
|
||||||
gtag('config', id, { anonymize_ip: true })
|
gtag('config', id, { anonymize_ip: true });
|
||||||
})()
|
})();
|
||||||
|
|||||||
@@ -95,7 +95,9 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container faq">
|
<a href="#main-content" class="skip-link">Skip to main content</a>
|
||||||
|
<div class="content">
|
||||||
|
<main id="main-content" class="container faq">
|
||||||
<nav aria-label="Breadcrumb">
|
<nav aria-label="Breadcrumb">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li><a href="/">Home</a></li>
|
<li><a href="/">Home</a></li>
|
||||||
@@ -106,8 +108,8 @@
|
|||||||
<div class="intro">
|
<div class="intro">
|
||||||
<strong>Let's get your inbox ready! 📬</strong><br />
|
<strong>Let's get your inbox ready! 📬</strong><br />
|
||||||
<p>
|
<p>
|
||||||
Friendly help for setting up your email—works with Outlook,
|
Friendly help for setting up your email—works with
|
||||||
Apple Mail, Thunderbird, phones, and more.
|
Outlook, Apple Mail, Thunderbird, phones, and more.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -175,8 +177,8 @@
|
|||||||
<li>Go to <b>File → Add Account</b></li>
|
<li>Go to <b>File → Add Account</b></li>
|
||||||
<li>Enter your full email address</li>
|
<li>Enter your full email address</li>
|
||||||
<li>
|
<li>
|
||||||
Choose <b>Advanced options</b> → check “Set up
|
Choose <b>Advanced options</b> → check “Set
|
||||||
manually”
|
up manually”
|
||||||
</li>
|
</li>
|
||||||
<li>Select <b>IMAP</b> (recommended) or POP</li>
|
<li>Select <b>IMAP</b> (recommended) or POP</li>
|
||||||
<li>
|
<li>
|
||||||
@@ -187,7 +189,8 @@
|
|||||||
<li>
|
<li>
|
||||||
Outgoing server:
|
Outgoing server:
|
||||||
<code>mail.mifi.holdings</code>, port
|
<code>mail.mifi.holdings</code>, port
|
||||||
<b>587</b> (STARTTLS) or <b>465</b> (SSL/TLS)
|
<b>587</b> (STARTTLS) or
|
||||||
|
<b>465</b> (SSL/TLS)
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Username: full email address; Password: your
|
Username: full email address; Password: your
|
||||||
@@ -196,8 +199,8 @@
|
|||||||
<li>Click <b>Connect</b></li>
|
<li>Click <b>Connect</b></li>
|
||||||
</ol>
|
</ol>
|
||||||
<span class="tip"
|
<span class="tip"
|
||||||
>If sending fails, make sure “Require logon using
|
>If sending fails, make sure “Require logon
|
||||||
SPA” is <b>unchecked</b>.</span
|
using SPA” is <b>unchecked</b>.</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -233,7 +236,9 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="accordion-content">
|
<div class="accordion-content">
|
||||||
<ol>
|
<ol>
|
||||||
<li>Menu → Account Settings → Add Mail Account</li>
|
<li>
|
||||||
|
Menu → Account Settings → Add Mail Account
|
||||||
|
</li>
|
||||||
<li>Fill in your name, email, and password</li>
|
<li>Fill in your name, email, and password</li>
|
||||||
<li>
|
<li>
|
||||||
Click “Configure manually” and use settings
|
Click “Configure manually” and use settings
|
||||||
@@ -246,20 +251,21 @@
|
|||||||
<!-- Mobile -->
|
<!-- Mobile -->
|
||||||
<section class="accordion-section">
|
<section class="accordion-section">
|
||||||
<button class="accordion-trigger" aria-expanded="false">
|
<button class="accordion-trigger" aria-expanded="false">
|
||||||
<span class="icon">▶</span> iOS / Android Mail / Gmail
|
<span class="icon">▶</span> iOS / Android Mail /
|
||||||
App
|
Gmail App
|
||||||
</button>
|
</button>
|
||||||
<div class="accordion-content">
|
<div class="accordion-content">
|
||||||
<ul>
|
<ul>
|
||||||
<li>Add Account → Other</li>
|
<li>Add Account → Other</li>
|
||||||
<li>Enter your email and password</li>
|
<li>Enter your email and password</li>
|
||||||
<li>
|
<li>
|
||||||
Manual setup: <code>mail.mifi.holdings</code>,
|
Manual setup:
|
||||||
correct ports, SSL/TLS required
|
<code>mail.mifi.holdings</code>, correct
|
||||||
|
ports, SSL/TLS required
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Gmail app: tap profile → Add account → Other,
|
Gmail app: tap profile → Add account →
|
||||||
fill in details, use IMAP
|
Other, fill in details, use IMAP
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -273,14 +279,14 @@
|
|||||||
<div class="accordion-content">
|
<div class="accordion-content">
|
||||||
<div class="faq-q">Q: My email won’t send?</div>
|
<div class="faq-q">Q: My email won’t send?</div>
|
||||||
<div class="faq-a">
|
<div class="faq-a">
|
||||||
Check that you’re using your full email address for
|
Check that you’re using your full email address
|
||||||
both incoming and outgoing username, and that the
|
for both incoming and outgoing username, and
|
||||||
port is 587 or 465.
|
that the port is 587 or 465.
|
||||||
</div>
|
</div>
|
||||||
<div class="faq-q">Q: SSL/TLS errors?</div>
|
<div class="faq-q">Q: SSL/TLS errors?</div>
|
||||||
<div class="faq-a">
|
<div class="faq-a">
|
||||||
Ensure SSL or STARTTLS is enabled for both incoming
|
Ensure SSL or STARTTLS is enabled for both
|
||||||
and outgoing mail.
|
incoming and outgoing mail.
|
||||||
</div>
|
</div>
|
||||||
<div class="faq-q">Q: Still stuck?</div>
|
<div class="faq-q">Q: Still stuck?</div>
|
||||||
<div class="faq-a">
|
<div class="faq-a">
|
||||||
@@ -288,8 +294,8 @@
|
|||||||
<a href="mailto:postmaster@mifi.holdings"
|
<a href="mailto:postmaster@mifi.holdings"
|
||||||
>postmaster@mifi.holdings</a
|
>postmaster@mifi.holdings</a
|
||||||
>.<br />
|
>.<br />
|
||||||
Please include any error messages, your mail app,
|
Please include any error messages, your mail
|
||||||
and a screenshot if you can!
|
app, and a screenshot if you can!
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -302,16 +308,17 @@
|
|||||||
<div class="accordion-content">
|
<div class="accordion-content">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<b>IMAP syncs</b> your mail everywhere—choose
|
<b>IMAP syncs</b> your mail
|
||||||
IMAP unless you know you want POP3.
|
everywhere—choose IMAP unless you know you
|
||||||
|
want POP3.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Your login is always your
|
Your login is always your
|
||||||
<b>full email address</b>.
|
<b>full email address</b>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Check your Spam/Junk folder for misfiled good
|
Check your Spam/Junk folder for misfiled
|
||||||
emails.
|
good emails.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Advanced: IMAP path prefix =
|
Advanced: IMAP path prefix =
|
||||||
@@ -322,56 +329,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
</main>
|
||||||
Email from mifi Ventures · Help Page – © 2025
|
</div>
|
||||||
|
<footer class="footer">
|
||||||
|
Email from mifi Holdings · Help Page · ©
|
||||||
|
2025<span id="current-year"></span>
|
||||||
mifi Ventures, LLC
|
mifi Ventures, LLC
|
||||||
</div>
|
</footer>
|
||||||
</div>
|
<script defer src="/assets/js/current-year.js"></script>
|
||||||
<script>
|
<script defer src="/assets/js/accordion.js"></script>
|
||||||
// Native accessible accordion
|
|
||||||
document.querySelectorAll('.accordion-trigger').forEach((btn) => {
|
|
||||||
btn.addEventListener('click', function () {
|
|
||||||
const section = btn.closest('.accordion-section')
|
|
||||||
const expanded =
|
|
||||||
btn.getAttribute('aria-expanded') === 'true'
|
|
||||||
document
|
|
||||||
.querySelectorAll('.accordion-section')
|
|
||||||
.forEach((s) => {
|
|
||||||
if (s === section) {
|
|
||||||
s.classList.toggle('open', !expanded)
|
|
||||||
btn.setAttribute(
|
|
||||||
'aria-expanded',
|
|
||||||
String(!expanded)
|
|
||||||
)
|
|
||||||
const content = btn.nextElementSibling
|
|
||||||
content.style.maxHeight = !expanded
|
|
||||||
? content.scrollHeight + 40 + 'px'
|
|
||||||
: '0px'
|
|
||||||
} else {
|
|
||||||
s.classList.remove('open')
|
|
||||||
s.querySelector(
|
|
||||||
'.accordion-trigger'
|
|
||||||
).setAttribute('aria-expanded', 'false')
|
|
||||||
s.querySelector(
|
|
||||||
'.accordion-content'
|
|
||||||
).style.maxHeight = '0px'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
// Allow arrow navigation
|
|
||||||
btn.addEventListener('keydown', function (e) {
|
|
||||||
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
|
||||||
const triggers = Array.from(
|
|
||||||
document.querySelectorAll('.accordion-trigger')
|
|
||||||
)
|
|
||||||
let idx = triggers.indexOf(e.target)
|
|
||||||
if (e.key === 'ArrowDown')
|
|
||||||
idx = (idx + 1) % triggers.length
|
|
||||||
else idx = (idx - 1 + triggers.length) % triggers.length
|
|
||||||
triggers[idx].focus()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -57,7 +57,9 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container text-center">
|
<a href="#main-content" class="skip-link">Skip to main content</a>
|
||||||
|
<div class="content">
|
||||||
|
<main id="main-content" class="container text-center">
|
||||||
<div class="emoji">📮</div>
|
<div class="emoji">📮</div>
|
||||||
<h1>This is just a mailbox.</h1>
|
<h1>This is just a mailbox.</h1>
|
||||||
<p>
|
<p>
|
||||||
@@ -67,14 +69,26 @@
|
|||||||
Looking for your messages?
|
Looking for your messages?
|
||||||
</p>
|
</p>
|
||||||
<a class="button" href="/help">Email Setup Help</a>
|
<a class="button" href="/help">Email Setup Help</a>
|
||||||
<a class="button" href="https://webmail.mifi.holdings"
|
<a
|
||||||
|
class="button"
|
||||||
|
href="https://webmail.mifi.holdings"
|
||||||
|
target="_blank"
|
||||||
>Go to Webmail</a
|
>Go to Webmail</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="button"
|
class="button"
|
||||||
href="https://postmaster.mifi.holdings/users/login.php"
|
href="https://postmaster.mifi.holdings/users/login.php"
|
||||||
|
target="_blank"
|
||||||
>Change/Forgot Password</a
|
>Change/Forgot Password</a
|
||||||
>
|
>
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
<footer class="footer">
|
||||||
|
Email from mifi Holdings · © 2025<span
|
||||||
|
id="current-year"
|
||||||
|
></span>
|
||||||
|
mifi Ventures, LLC
|
||||||
|
</footer>
|
||||||
|
<script defer src="/assets/js/current-year.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export default {
|
|||||||
extends: ['stylelint-config-standard'],
|
extends: ['stylelint-config-standard'],
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ['src/**/*.css']
|
files: ['src/**/*.css'],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user