milestone 23 s3: move srOnly into the shared style vocabulary
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user