Refactor web frontend and remove unnecessary dependencies.
- Eliminate frontend JS build step completely: (remove dep: NodeJS, npx, tailwind, postcss, autoprefixer) - Declutter and cleanup index.html (8.49 KB to 3.4 KB) = ~60% savings. - Replace tailwind with custom CSS (10.64 KB to 1.96 KB) = ~81% savings. - Remove Google font (~100 KB) as there is very little text on the page. - Refactor and cleanup main.js and remove tailwind styling logic. (2.82 KB to 1.12 KB) = ~60% savings. - Net static asset reduction = 21.95 KB to 6.48 KB = ~70% savings apart from the 100+ KB elimination of Google fonts.pull/18/head
parent
0dc61ac8ec
commit
b8ba782cf3
10
Makefile
10
Makefile
|
@ -9,18 +9,10 @@ VERSION := ${HASH}
|
||||||
build-cli:
|
build-cli:
|
||||||
go build -o ${CLI_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/cli/
|
go build -o ${CLI_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/cli/
|
||||||
|
|
||||||
.PHONY: build-frontend
|
|
||||||
build-frontend:
|
|
||||||
cd cmd/doggo/api && NODE_ENV=production npx tailwindcss build -o ./assets/tailwind.css
|
|
||||||
|
|
||||||
.PHONY: build-api
|
.PHONY: build-api
|
||||||
build-api:
|
build-api:
|
||||||
go build -o ${API_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/api/
|
go build -o ${API_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/api/
|
||||||
|
|
||||||
.PHONY: deps
|
|
||||||
deps:
|
|
||||||
cd cmd/doggo/api && npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
|
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: build-api build-cli
|
build: build-api build-cli
|
||||||
|
|
||||||
|
@ -29,7 +21,7 @@ run-cli: build-cli ## Build and Execute the CLI binary after the build step.
|
||||||
${CLI_BIN}
|
${CLI_BIN}
|
||||||
|
|
||||||
.PHONY: run-api
|
.PHONY: run-api
|
||||||
run-api: build-frontend build-api ## Build and Execute the API binary after the build step.
|
run-api: build-api ## Build and Execute the API binary after the build step.
|
||||||
${API_BIN} --config config-api-sample.toml
|
${API_BIN} --config config-api-sample.toml
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
|
@ -1,154 +1,90 @@
|
||||||
const $ = document.querySelector.bind(document);
|
const $ = document.querySelector.bind(document);
|
||||||
const $new = document.createElement.bind(document);
|
const $new = document.createElement.bind(document);
|
||||||
const apiURL = "/api/lookup/";
|
const $show = (el) => {
|
||||||
const isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
|
el.classList.remove('hidden');
|
||||||
|
};
|
||||||
function handleNSChange() {
|
const $hide = (el) => {
|
||||||
if ($('select[name=ns]').value == "custom") {
|
el.classList.add('hidden');
|
||||||
$('div[id=custom_ns]').classList.remove("hidden");
|
};
|
||||||
$('div[id=ns]').classList.add("hidden");
|
|
||||||
} else {
|
|
||||||
$('div[id=custom_ns]').classList.add("hidden");
|
|
||||||
$('div[id=ns]').classList.remove("hidden");
|
|
||||||
$('input[name=ns]').placeholder = $('select[name=ns]').value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Source: https://stackoverflow.com/a/1026087.
|
|
||||||
function capitalizeFirstLetter(string) {
|
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', (event) => {
|
|
||||||
handleNSChange();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const apiURL = '/api/lookup/';
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
const fields = ['name', 'address', 'type', 'ttl', 'rtt', 'nameserver'];
|
const fields = ['name', 'address', 'type', 'ttl', 'rtt'];
|
||||||
|
|
||||||
// createRow creates a table row with the given cell values.
|
// createRow creates a table row with the given cell values.
|
||||||
function createRow(item) {
|
function createRow(item) {
|
||||||
const tr = $new('tr');
|
const tr = $new('tr');
|
||||||
fields.forEach((f) => {
|
fields.forEach((f) => {
|
||||||
const td = $new('td');
|
const td = $new('td');
|
||||||
td.classList.add("px-6", "py-4", "whitespace-nowrap", "text-sm");
|
|
||||||
if (f == "ttl" || f == "rtt" || f == "nameserver") {
|
|
||||||
td.classList.add("text-gray-500");
|
|
||||||
} else {
|
|
||||||
td.classList.add("text-gray-900");
|
|
||||||
}
|
|
||||||
if (f == "name") {
|
|
||||||
td.classList.add("font-semibold");
|
|
||||||
}
|
|
||||||
if (f == "type") {
|
|
||||||
td.innerHTML = '<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">' + item[f] + '</span>';
|
|
||||||
} else {
|
|
||||||
td.innerText = item[f];
|
td.innerText = item[f];
|
||||||
}
|
td.classList.add(f);
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
});
|
});
|
||||||
return tr;
|
return tr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
const tbody = $('#table tbody'),
|
||||||
|
tbl = $('#table');
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
$hide(tbl);
|
||||||
|
|
||||||
// `createList` creates a table row with the given cell values.
|
const q = $('input[name=q]').value.trim(),
|
||||||
function createList(item) {
|
typ = $('select[name=type]').value,
|
||||||
const ul = $new('ul');
|
addr = $('input[name=address]').value.trim();
|
||||||
ul.classList.add("m-4", "block", "bg-indigo-100");
|
|
||||||
fields.forEach((f) => {
|
|
||||||
const li = $new('li');
|
|
||||||
const span = $new('span');
|
|
||||||
span.classList.add("p-2", "text-gray-500", "font-semibold");
|
|
||||||
span.innerText = capitalizeFirstLetter(f) + ': ' + item[f]
|
|
||||||
li.appendChild(span);
|
|
||||||
ul.appendChild(li);
|
|
||||||
});
|
|
||||||
return ul;
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareNSAddr(ns) {
|
// Post to the API.
|
||||||
switch (ns) {
|
const req = await fetch(apiURL, {
|
||||||
// If it's a custom nameserver, get the value from the user's input.
|
|
||||||
case "custom":
|
|
||||||
return $('input[name=custom_ns]').value.trim()
|
|
||||||
// Else get it from the select dropdown field.
|
|
||||||
default:
|
|
||||||
return $('select[name=ns]').value.trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const postForm = body => {
|
|
||||||
return fetch(apiURL, {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: { 'Content-Type': 'application/json' },
|
||||||
'Content-Type': 'application/json'
|
body: JSON.stringify({ query: [q,], type: [typ,], nameservers: [addr,] })
|
||||||
},
|
|
||||||
body
|
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const res = await req.json();
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const tbl = $('table tbody');
|
if (res.status != 'success') {
|
||||||
const list = $('div[id=mobile-answers-sec]');
|
|
||||||
tbl.innerHTML = '';
|
|
||||||
list.innerHTML = '';
|
|
||||||
|
|
||||||
$('p[id=empty-name-sec]').classList.add("hidden");
|
|
||||||
const errSec = $('div[id=api-error-sec]');
|
|
||||||
errSec.classList.add("hidden");
|
|
||||||
|
|
||||||
const q = $('input[name=q]').value.trim(), typ = $('select[name=type]').value;
|
|
||||||
const ns = $('select[name=ns]').value;
|
|
||||||
|
|
||||||
if (!q) {
|
|
||||||
$('p[id=empty-name-sec]').classList.remove("hidden");
|
|
||||||
throw ('Invalid query name.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!q || !typ || !ns) {
|
|
||||||
throw ('Invalid or empty query params.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const nsAddr = prepareNSAddr(ns);
|
|
||||||
const body = JSON.stringify({ query: [q,], type: [typ,], nameservers: [nsAddr,] });
|
|
||||||
|
|
||||||
const response = await postForm(body);
|
|
||||||
const res = await response.json();
|
|
||||||
if (res.status != "success") {
|
|
||||||
// get error message from body or default to response statusText
|
|
||||||
const error = (res && res.message) || response.statusText;
|
const error = (res && res.message) || response.statusText;
|
||||||
errSec.classList.remove("hidden");
|
|
||||||
errSec.innerHTML = '<p class="text-xl text-red-500">' + error + '</p>'
|
|
||||||
throw(error);
|
throw(error);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.data[0].answers == null) {
|
if (res.data[0].answers == null) {
|
||||||
const errSec = $('div[id=api-error-sec]');
|
throw('No records found.');
|
||||||
errSec.classList.remove("hidden");
|
return;
|
||||||
errSec.innerHTML = '<p class="text-xl text-red-500">' + 'No records found!' + '</p>'
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$('div[id=answer_sec]').classList.remove("hidden");
|
|
||||||
|
|
||||||
if (isMobile === true) {
|
|
||||||
list.classList.remove("hidden");
|
|
||||||
res.data[0].answers.forEach((item) => {
|
res.data[0].answers.forEach((item) => {
|
||||||
console.log("appending", item)
|
tbody.appendChild(createRow(item));
|
||||||
list.appendChild(createList(item));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
$show(tbl);
|
||||||
res.data[0].answers.forEach((item) => {
|
|
||||||
tbl.appendChild(createRow(item));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
document.querySelector('form').addEventListener('submit', handleSubmit);
|
// Capture the form submit.
|
||||||
|
$('#form').onsubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const msg = $('#message');
|
||||||
|
$hide(msg);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await handleSubmit();
|
||||||
|
} catch(e) {
|
||||||
|
msg.innerText = e.toString();
|
||||||
|
$show(msg);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Change the address on ns change.
|
||||||
|
const ns = $("#ns"), addr = $("#address");
|
||||||
|
addr.value = ns.value;
|
||||||
|
|
||||||
|
ns.onchange = (e) => {
|
||||||
|
addr.value = e.target.value;
|
||||||
|
if(addr.value === "") {
|
||||||
|
addr.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
})();
|
})();
|
|
@ -0,0 +1,195 @@
|
||||||
|
:root {
|
||||||
|
--primary: #4338ca;
|
||||||
|
--secondary: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Segoe UI", "Helvetica Neue", Inter, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #111;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select, button {
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
padding: 10px 15px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
input:focus, select:focus {
|
||||||
|
border-color: var(--primary);
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
border-color: var(--primary);
|
||||||
|
background: var(--primary);
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
width: auto;
|
||||||
|
padding: 10px 30px;
|
||||||
|
}
|
||||||
|
button:focus,
|
||||||
|
button:hover {
|
||||||
|
border-color: var(--secondary);
|
||||||
|
background: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
box-shadow: 1px 1px 4px #eee;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
margin: 60px auto 30px auto;
|
||||||
|
max-width: 900px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.5em;
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
|
.logo span {
|
||||||
|
color: var(--primary);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-bottom: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.row .field {
|
||||||
|
flex: 50%;
|
||||||
|
}
|
||||||
|
.row .field:last-child {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.help {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.875em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#message {
|
||||||
|
color: #ff3300;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.box {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
table th {
|
||||||
|
background: #f9fafb;
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.875em;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
table th, tbody td {
|
||||||
|
padding: 10px 15px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
td.name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
th.type, td.type {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
td.type {
|
||||||
|
background: #d1fae5;
|
||||||
|
color: #065f46;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin: 60px 0 0 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
footer a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media (max-width: 650px) {
|
||||||
|
.main {
|
||||||
|
margin: 60px 30px 30px 30px;
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.field {
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
}
|
||||||
|
.row .field:last-child {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.submit button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
table th {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
table tr {
|
||||||
|
border-bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
table td {
|
||||||
|
border: 1px solid #eee;
|
||||||
|
margin: 0 -1px -1px 0;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
word-wrap:break-word;
|
||||||
|
}
|
||||||
|
table th.type, table td.type {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
table td span {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,54 +1,26 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Doggo DNS</title>
|
<title>Doggo DNS</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
|
||||||
|
<link href="assets/style.css" rel="stylesheet">
|
||||||
<link href="assets/tailwind.css" rel="stylesheet">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap" rel="stylesheet">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: 'Poppins', sans-serif;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
<body>
|
||||||
<noscript>
|
<div class="main">
|
||||||
<div class="noscript">
|
<header>
|
||||||
<h2>This service requires Javascript</h2>
|
<h1 class="logo"><span>Doggo</span> DNS</h1>
|
||||||
<p>Please enable JavaScript so that the form data can be sent to the API backend.</p>
|
|
||||||
</div>
|
|
||||||
</noscript>
|
|
||||||
|
|
||||||
<body class="p-10 max-w-screen-lg m-auto min-h-screen flex flex-col">
|
|
||||||
<header class="mt-10">
|
|
||||||
<h1 class="text-5xl font-black text-center"><span class="text-indigo-700">Doggo</span> DNS</h1>
|
|
||||||
</header>
|
</header>
|
||||||
<main id="app" class="main flex flex-col flex-grow">
|
|
||||||
<form>
|
<form method="post" id="form" class="box">
|
||||||
<div class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 flex flex-col my-2">
|
<div class="row">
|
||||||
<div class="-mx-3 md:flex mb-6">
|
<div class="field">
|
||||||
<div class="md:w-1/2 px-3 mb-6 md:mb-0">
|
<label for="domain">Domain name</label>
|
||||||
<label>
|
<input id="domain" name="q" placeholder="domain.tld" required autofocus />
|
||||||
Domain Name
|
|
||||||
</label>
|
|
||||||
<input required autofocus name="q" type="text" placeholder="domain.tld"
|
|
||||||
class="w-full border-gray-300 rounded-lg shadown-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
||||||
<p id="empty-name-sec" class="hidden text-red-500 text-xs">Please enter a domain name to
|
|
||||||
query.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="md:w-1/2 px-3">
|
<div class="field">
|
||||||
<label>
|
<label for="type">Query type</label>
|
||||||
Query Type
|
<select id="type" name="type">
|
||||||
</label>
|
|
||||||
<select name="type"
|
|
||||||
class="w-full border-gray-300 rounded-lg shadown-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
||||||
<option default>A</option>
|
<option default>A</option>
|
||||||
<option>AAAA</option>
|
<option>AAAA</option>
|
||||||
<option>CAA</option>
|
<option>CAA</option>
|
||||||
|
@ -63,113 +35,66 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="-mx-3 md:flex">
|
<div class="row">
|
||||||
<div class="md:w-1/2 px-3 mb-6 md:mb-0">
|
<div class="field">
|
||||||
<label>
|
<label for="ns">Nameserver</label>
|
||||||
Nameserver
|
<select id="ns" name="ns">
|
||||||
</label>
|
|
||||||
<select name="ns" onchange="handleNSChange()"
|
|
||||||
class="w-full border-gray-300 rounded-lg shadown-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
||||||
<option default value="tcp://1.1.1.1:53">Cloudflare</option>
|
<option default value="tcp://1.1.1.1:53">Cloudflare</option>
|
||||||
<option value="https://cloudflare-dns.com/dns-query">Cloudflare (DOH)</option>
|
<option value="https://cloudflare-dns.com/dns-query">Cloudflare (DOH)</option>
|
||||||
<option value="tcp://8.8.8.8:53">Google</option>
|
<option value="tcp://8.8.8.8:53">Google</option>
|
||||||
<option value="tcp://9.9.9.9:53">Quad9</option>
|
<option value="tcp://9.9.9.9:53">Quad9</option>
|
||||||
<option value="custom">Custom</option>
|
<option value="">Custom</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="md:w-1/2 px-3">
|
<div class="field">
|
||||||
<label for="grid-zip">
|
<label for="address">Nameserver address</label>
|
||||||
Address
|
<input id="address" name="address" type="text" placeholder="tcp://your-ip"
|
||||||
</label>
|
required pattern="(tcp|udp|tls|https):\/\/(.*)" />
|
||||||
<div id="custom_ns" class="hidden">
|
<p class="help">
|
||||||
<input name="custom_ns" type="text" placeholder="Enter Nameserver address"
|
To use different protocols like DOH, DOT etc. refer to the instructions
|
||||||
class="w-full border-gray-300 rounded-lg shadown-sm focus:border-indigo-500 focus:ring-indigo-500">
|
<a href="https://github.com/mr-karan/doggo#transport-options">here</a>.
|
||||||
<p class="mt-2 text-grey-darker text-xs">To use different protocols like DOH, DOT etc. refer
|
</p>
|
||||||
to the
|
|
||||||
instructions <a class="font-semibold"
|
|
||||||
href="https://github.com/mr-karan/doggo#transport-options">here</a>.</p>
|
|
||||||
</div>
|
|
||||||
<div id="ns">
|
|
||||||
<input readonly name="ns" type="text"
|
|
||||||
class="bg-gray-50 w-full border-gray-300 rounded-lg shadown-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="row">
|
||||||
<div class="mt-8 text-right">
|
<div class="field"><p id="message"></p></div>
|
||||||
<button class="w-full sm:w-auto flex-none bg-indigo-700 hover:bg-indigo-500
|
<div class="field submit">
|
||||||
text-white text-lg leading-6 font-semibold py-3 px-6 border border-transparent rounded
|
<button type="submit">Submit</button>
|
||||||
focus:ring-2 focus:ring-offset-2 focus:ring-offset-white focus:ring-indigo-700 focus:outline-none
|
|
||||||
transition-colors duration-400">
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!--Responses-->
|
<!--Responses-->
|
||||||
<div id="answer_sec" class="hidden mt-12 flex flex-col">
|
<table class="box hidden" id="table">
|
||||||
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8 sm:block hidden">
|
<thead>
|
||||||
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
|
||||||
<div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
|
|
||||||
<table class="min-w-full divide-y divide-gray-200">
|
|
||||||
<thead class="bg-gray-50">
|
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col"
|
<th>Name</th>
|
||||||
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
|
<th>Address</th>
|
||||||
Name
|
<th class="type">Type</th>
|
||||||
</th>
|
<th>TTL</th>
|
||||||
<th scope="col"
|
<th>RTT</th>
|
||||||
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
|
|
||||||
Address
|
|
||||||
</th>
|
|
||||||
<th scope="col"
|
|
||||||
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
|
|
||||||
Type
|
|
||||||
</th>
|
|
||||||
<th scope="col"
|
|
||||||
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
|
|
||||||
TTL
|
|
||||||
</th>
|
|
||||||
<th scope="col"
|
|
||||||
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
|
|
||||||
RTT
|
|
||||||
</th>
|
|
||||||
<th scope="col"
|
|
||||||
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
|
|
||||||
Nameserver
|
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody></tbody>
|
||||||
<!--tr is added by JS-->
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--On Mobile-->
|
|
||||||
<div id="mobile-answers-sec" class="hidden">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--No Answers-->
|
<footer >
|
||||||
<div id="no-answers-sec" class="hidden mt-12 text-center">
|
<div>
|
||||||
<p class="text-xl text-gray-900">Oops! Found no records for this query.</p>
|
<p>Built with
|
||||||
</div>
|
<span>♥</span> by
|
||||||
|
<a href="https://mrkaran.dev"><strong>mrkaran</strong></a>
|
||||||
<!--Show Error-->
|
</p>
|
||||||
<div id="api-error-sec" class="hidden mt-12 text-center">
|
<p><a href="https://github.com/mr-karan/doggo">Source Code</a></p>
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="p-10">
|
|
||||||
<div class="container mx-auto flex flex-col items-center justify-center">
|
|
||||||
<p class="text-xl font-bold">Built with <span style=" color: #4338ca;">♥</span> by <a
|
|
||||||
href="https://mrkaran.dev"><span class="text-indigo-700 font-semibold">mrkaran</span></a></p>
|
|
||||||
<p class="text-center"><a href="https://github.com/mr-karan/doggo">Source Code</a></p>
|
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="assets/main.js"> </script>
|
<script src="assets/main.js"> </script>
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<div class="noscript">
|
||||||
|
<h2>This service requires Javascript</h2>
|
||||||
|
<p>Please enable JavaScript so that the form data can be sent to the API backend.</p>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue