milestone 23 s3: move srOnly into the shared style vocabulary

This commit is contained in:
2026-08-12 22:16:58 +02:00
parent bb39539fdf
commit 0f58966b31
8 changed files with 33 additions and 76 deletions
+14 -4
View File
@@ -1,9 +1,19 @@
# nxdns # nxdns
A self-hosted DNS sinkhole for a household LAN, written in Zig 0.16. One nxdns is a DNS sinkhole for your LAN. It blocks the names you do not want, and
static musl binary, SQLite for state, a Raspberry Pi 5 as the reference forwards the rest over an encrypted connection.
target. It answers your network's DNS, blocks what you tell it to, and shows
you what asked for what. ```mermaid
flowchart LR
devices["Your devices"] -- "DNS query" --> nxdns["nxdns"]
nxdns -- "answer" --> devices
nxdns -- "allowed" --> upstream["Upstream resolvers<br/>DoH / DoT"]
upstream -- "answer" --> nxdns
nxdns -- "blocked" --> sink["0.0.0.0 / NXDOMAIN"]
```
One static Zig binary. SQLite holds the state and the query log, which the web
UI, the REST API and `/metrics` read.
## Features ## Features
+1 -12
View File
@@ -79,17 +79,6 @@ const styles = stylex.create({
dimWhenDisabled: { dimWhenDisabled: {
opacity: { default: 1, ":disabled": 0.5 }, opacity: { default: 1, ":disabled": 0.5 },
}, },
srOnly: {
position: "absolute",
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clipPath: "inset(50%)",
whiteSpace: "nowrap",
borderWidth: 0,
},
}); });
export default function BlocklistsPage() { export default function BlocklistsPage() {
@@ -170,7 +159,7 @@ export default function BlocklistsPage() {
<th {...stylex.props(shared.th)}>Skipped regex</th> <th {...stylex.props(shared.th)}>Skipped regex</th>
<th {...stylex.props(shared.th)}>Last updated</th> <th {...stylex.props(shared.th)}>Last updated</th>
<th {...stylex.props(shared.th)}> <th {...stylex.props(shared.th)}>
<span {...stylex.props(styles.srOnly)}>Actions</span> <span {...stylex.props(shared.srOnly)}>Actions</span>
</th> </th>
</tr> </tr>
</thead> </thead>
+1 -12
View File
@@ -96,17 +96,6 @@ const styles = stylex.create({
* The accessible name of the actions column, kept out of the visual table * The accessible name of the actions column, kept out of the visual table
* without leaving the accessibility tree. * without leaving the accessibility tree.
*/ */
srOnly: {
position: "absolute",
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clipPath: "inset(50%)",
whiteSpace: "nowrap",
borderWidth: 0,
},
}); });
export default function ClientsPage() { export default function ClientsPage() {
@@ -138,7 +127,7 @@ export default function ClientsPage() {
<th {...stylex.props(styles.cell)}>First seen</th> <th {...stylex.props(styles.cell)}>First seen</th>
<th {...stylex.props(styles.cell)}>Last seen</th> <th {...stylex.props(styles.cell)}>Last seen</th>
<th {...stylex.props(styles.cell)}> <th {...stylex.props(styles.cell)}>
<span {...stylex.props(styles.srOnly)}>Actions</span> <span {...stylex.props(shared.srOnly)}>Actions</span>
</th> </th>
</tr> </tr>
</thead> </thead>
+1 -12
View File
@@ -91,17 +91,6 @@ const styles = stylex.create({
dimWhenDisabled: { dimWhenDisabled: {
opacity: { default: 1, ":disabled": 0.5 }, opacity: { default: 1, ":disabled": 0.5 },
}, },
srOnly: {
position: "absolute",
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clipPath: "inset(50%)",
whiteSpace: "nowrap",
borderWidth: 0,
},
}); });
function RecordForm({ function RecordForm({
@@ -268,7 +257,7 @@ export default function RecordsTab() {
TTL TTL
</th> </th>
<th scope="col" {...stylex.props(styles.headCellLast)}> <th scope="col" {...stylex.props(styles.headCellLast)}>
<span {...stylex.props(styles.srOnly)}>Actions</span> <span {...stylex.props(shared.srOnly)}>Actions</span>
</th> </th>
</tr> </tr>
</thead> </thead>
+1 -12
View File
@@ -87,17 +87,6 @@ const styles = stylex.create({
dimWhenDisabled: { dimWhenDisabled: {
opacity: { default: 1, ":disabled": 0.5 }, opacity: { default: 1, ":disabled": 0.5 },
}, },
srOnly: {
position: "absolute",
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clipPath: "inset(50%)",
whiteSpace: "nowrap",
borderWidth: 0,
},
}); });
function ZoneForm({ function ZoneForm({
@@ -232,7 +221,7 @@ export default function ZonesTab() {
Resolver Resolver
</th> </th>
<th scope="col" {...stylex.props(styles.headCellLast)}> <th scope="col" {...stylex.props(styles.headCellLast)}>
<span {...stylex.props(styles.srOnly)}>Actions</span> <span {...stylex.props(shared.srOnly)}>Actions</span>
</th> </th>
</tr> </tr>
</thead> </thead>
+1 -12
View File
@@ -78,17 +78,6 @@ const styles = stylex.create({
submitRow: { submitRow: {
display: "flex", display: "flex",
}, },
srOnly: {
position: "absolute",
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clipPath: "inset(50%)",
whiteSpace: "nowrap",
borderWidth: 0,
},
}); });
export default function RulesPage() { export default function RulesPage() {
@@ -137,7 +126,7 @@ export default function RulesPage() {
<th {...stylex.props(shared.th)}>Group</th> <th {...stylex.props(shared.th)}>Group</th>
<th {...stylex.props(shared.th)}>Created</th> <th {...stylex.props(shared.th)}>Created</th>
<th {...stylex.props(shared.th)}> <th {...stylex.props(shared.th)}>
<span {...stylex.props(styles.srOnly)}>Actions</span> <span {...stylex.props(shared.srOnly)}>Actions</span>
</th> </th>
</tr> </tr>
</thead> </thead>
+1 -12
View File
@@ -53,17 +53,6 @@ const styles = stylex.create({
dimWhenDisabled: { dimWhenDisabled: {
opacity: { default: 1, ":disabled": 0.5 }, opacity: { default: 1, ":disabled": 0.5 },
}, },
srOnly: {
position: "absolute",
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clipPath: "inset(50%)",
whiteSpace: "nowrap",
borderWidth: 0,
},
}); });
export default function UpstreamsPage() { export default function UpstreamsPage() {
@@ -127,7 +116,7 @@ export default function UpstreamsPage() {
<th {...stylex.props(shared.th)}>Enabled</th> <th {...stylex.props(shared.th)}>Enabled</th>
<th {...stylex.props(shared.th)}>TLS name</th> <th {...stylex.props(shared.th)}>TLS name</th>
<th {...stylex.props(shared.th)}> <th {...stylex.props(shared.th)}>
<span {...stylex.props(styles.srOnly)}>Actions</span> <span {...stylex.props(shared.srOnly)}>Actions</span>
</th> </th>
</tr> </tr>
</thead> </thead>
+13
View File
@@ -151,6 +151,19 @@ export const styles = stylex.create({
color: colors.dangerText, color: colors.dangerText,
}, },
/** Visible to a screen reader only; the element keeps its place in the a11y tree. */
srOnly: {
position: "absolute",
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clipPath: "inset(50%)",
whiteSpace: "nowrap",
borderWidth: 0,
},
th: { th: {
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomStyle: "solid", borderBottomStyle: "solid",