Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ COPY gleam.toml manifest.toml ./

RUN gleam deps download

COPY src/ ./src/
COPY themes/ ./themes/
COPY scripts/ ./scripts/

RUN ./scripts/sync-themes.sh

COPY src/ ./src/

RUN gleam export erlang-shipment

FROM erlang:27-alpine
Expand Down
2 changes: 1 addition & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# https://gleam.run/writing-gleam/gleam-toml/.

name = "mayu"
version = "0.1.28"
version = "0.1.29"
gleam = ">= 1.14.0"
description = "Moe-Counter Compatible Website Hit Counter"
licenses = ["GPL-3.0-only"]
Expand Down
44 changes: 34 additions & 10 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

<body>
<style>
@import url("https://fonts.googleapis.com/css2?family=Overpass:ital,wght@0,100..900;1,100..900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap");

body {
background-color: #0b1622;
Expand Down Expand Up @@ -295,12 +294,14 @@ <h2><label for="idInput">Username</label></h2>
// The server never decodes paths, so escaping more renames live counters.
const encodeNameForPath = (name) =>
name.replace(/#/g, "%23").replace(/\?/g, "%3F");

const escapeHtmlAttribute = (value) =>
value
.replaceAll("&", "&amp;")
.replaceAll('"', "&quot;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;");

const updateCounter = () => {
const counterName = idInput.value || "demo";
const theme = themeSelect.value;
Expand All @@ -314,8 +315,9 @@ <h2><label for="idInput">Username</label></h2>
const htmlName = escapeHtmlAttribute(counterName);
const htmlUrl = escapeHtmlAttribute(exampleImage.src);

copyCodes.innerText = `![${markdownName}](<${exampleImage.src}>)\n\n<img src="${htmlUrl}" alt="${htmlName}" />`;
copyCodes.textContent = `![${markdownName}](<${exampleImage.src}>)\n\n<img src="${htmlUrl}" alt="${htmlName}" />`;
};

const mascots = [
{ name: "Akaza Akari", image: "https://i.imgur.com/efamPLp.png" },
{ name: "Akemi Homura", image: "https://i.imgur.com/8v6aSbV.png" },
Expand Down Expand Up @@ -360,6 +362,29 @@ <h2><label for="idInput">Username</label></h2>
{ name: "Yuzuki Yukari", image: "https://i.imgur.com/84HOYIc.png" },
];

const mascot = document.querySelector(".mascot");
const mascotMediaQuery = window.matchMedia("(min-width: 768px)");

const loadMascot = () => {
if (!mascotMediaQuery.matches) {
return;
}

const randomMascot = mascots[Math.floor(Math.random() * mascots.length)];

mascot.src = randomMascot.image;
mascot.alt = randomMascot.name;
mascot.title = randomMascot.name;

mascot.classList.add("loaded");

if (mascotMediaQuery.removeEventListener) {
mascotMediaQuery.removeEventListener("change", loadMascot);
} else {
mascotMediaQuery.removeListener(loadMascot);
}
};

updateCounter();
idInput.addEventListener("input", () => {
clearTimeout(inputTimeout);
Expand All @@ -368,14 +393,13 @@ <h2><label for="idInput">Username</label></h2>
});
themeSelect.addEventListener("change", updateCounter);

const randomMascot = mascots[Math.floor(Math.random() * mascots.length)];
const mascot = document.querySelector(".mascot");

mascot.src = randomMascot.image;
mascot.alt = randomMascot.name;
mascot.title = randomMascot.name;
if (mascotMediaQuery.addEventListener) {
mascotMediaQuery.addEventListener("change", loadMascot);
} else {
mascotMediaQuery.addListener(loadMascot);
}

mascot.classList.add("loaded");
loadMascot();
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion src/database.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn setup_sqlite(connection) {
let assert Ok(_) =
sqlight.exec(
"create table if not exists tb_count (
id integer primary key autoincrement not null unique,
id integer primary key autoincrement not null,
name text not null unique,
num int not null default (0)
) strict;",
Expand Down
52 changes: 52 additions & 0 deletions test/mayu_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,62 @@ pub fn setup_migrates_legacy_moe_counter_table_test() {

let assert Ok(counter) =
database.get_counter(database.Sqlite(connection), "legacy")
let assert Ok(index_counts) =
sqlight.query(
"select count(*) from pragma_index_list('tb_count');",
on: connection,
with: [],
expecting: decode.at([0], decode.int),
)

counter.num |> should.equal(42)
counter.created_at |> should.equal("")
counter.updated_at |> should.not_equal("")
index_counts |> should.equal([2])
}

pub fn setup_preserves_sqlite_identity_and_name_constraints_test() {
use connection <- sqlight.with_connection(":memory:")

database.setup(database.Sqlite(connection))
database.setup(database.Sqlite(connection))

let assert Ok(indexed_columns) =
sqlight.query(
"select name from pragma_index_info('sqlite_autoindex_tb_count_1');",
on: connection,
with: [],
expecting: decode.at([0], decode.string),
)
let assert Ok(_) =
sqlight.exec(
"insert into tb_count (id, name) values (128, 'first');",
connection,
)
let assert Error(_) =
sqlight.exec(
"insert into tb_count (id, name) values (128, 'duplicate-id');",
connection,
)
let assert Error(_) =
sqlight.exec("insert into tb_count (name) values ('first');", connection)
let assert Ok(_) =
sqlight.exec(
"delete from tb_count where name = 'first';
insert into tb_count (name) values ('second');",
connection,
)
let assert Ok(identities) =
sqlight.query(
"select id from tb_count where name = 'second';",
on: connection,
with: [],
expecting: decode.at([0], decode.int),
)

indexed_columns |> should.equal(["name"])
identities |> should.equal([129])
remaining_names(connection) |> should.equal(["second"])
}

pub fn prune_removes_only_idle_low_count_test() {
Expand Down
Loading