Merge pull request #8 from GandalfDG/feat_bulma_ui

Convert Browser Action Popup to use Bulma CSS
This commit is contained in:
Jack Case
2025-11-23 09:17:50 -05:00
committed by GitHub
7 changed files with 167 additions and 47 deletions

4
.gitignore vendored
View File

@@ -1,3 +1,5 @@
scripts/
node_modules/
package/
package/
package.zip

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Slop Farmer",
"version": "0.4.1",
"version": "0.5.1",
"author": "Jack Case",
"description": "Crowd-source AI slop pages and domains",
@@ -13,10 +13,9 @@
"*://*.duckduckgo.com/*"
],
"content_security_policy": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; worker-src 'self' blob:",
"content_security_policy": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; worker-src 'self'",
"browser_action": {
"default_icon": "icons/virus_black_32.png",
"default_title": "Slop Farmer",
"default_popup": "pages/action_popup.html",
"default_area": "navbar",
@@ -44,5 +43,16 @@
"matches": ["*://*.duckduckgo.com/*q=*"],
"js": ["scripts/content-script.js"]
}
]
],
"browser_specific_settings": {
"gecko": {
"data_collection_permissions": {
"required": [
"authenticationInfo",
"personallyIdentifyingInfo"
]
}
}
}
}

View File

@@ -1,51 +1,86 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<!-- <script async defer src="https://cdn.jsdelivr.net/gh/altcha-org/altcha/dist/altcha.min.js" type="module"></script> -->
<script async src="/scripts/browser-action.js" type="module"></script>
<script async defer src="/scripts/altcha/dist/altcha.js" type="module"></script>
<link rel="stylesheet" href="/styles/bulma/bulma.min.css">
<title>Slop Farmer</title>
</head>
<body>
<nav>
<button id="signup-select" type="button">sign up</button>
<button id="login-select" type="button">log in</button>
</nav>
<div id="onboarding" style="visibility: visible;">
<h1>Welcome, Slop Farmer!</h1>
<p>tired of ai-generated slop articles in your search results? Sign up or log in to start reporting slop articles
and have reported slop flagged in your searches!
</p>
<div id="onboarding" style="visibility: visible;" class="hero is-primary not-logged-in">
<div class="hero-body">
<h1 class="title">Welcome, Slop Farmer!</h1>
<p>tired of ai-generated slop articles in your search results? Sign up or log in to start reporting slop
articles and have reported slop flagged in your searches!</p>
</div>
</div>
<div id="signup" style="visibility: collapse;">
<form id="signup-form">
<label for="email">email</label>
<input type="email" name="email" required />
<label for="password">password</label>
<input type="password" name="password" required />
<altcha-widget challengeurl="https://api.slopfarmer.jack-case.pro/altcha-challenge"></altcha-widget>
<button id="signup-button">sign up</button>
</form>
<h2></h2>
</div>
<button id="logout-button" class="button is-small logged-in">Logout</button>
<div id="login" style="visibility: collapse;">
<h1>Log in to enable slop checking and reporting</h1>
<form id="login-form">
<label for="email" id="username">username</label>
<input type="text" name="username" required />
<label for="password" id="password">password</label>
<input type="password" name="password" required />
<button id="login-button">login</button>
</form>
<h2 style="visibility: collapse;" id="login-status">You're logged in.</h2>
</div>
<div class="section">
<nav class="tabs is-centered not-logged-in">
<ul>
<li id="signup-tab"><a>sign up</a></li>
<li id="login-tab"><a>log in</a></li>
</ul>
</nav>
<div id="report" style="visibility: collapse;">
<button id="report-button">Report this page</button>
<h2></h2>
<div id="signup" style="display:block" class="box">
<h1 class="title">Sign Up</h1>
<form id="signup-form">
<div class="field">
<label for="email" class="label">E-Mail</label>
<div class="control">
<input type="email" name="email" required class="input" />
</div>
</div>
<div class="field">
<label for="password" class="label">Password</label>
<div class="control">
<input type="password" name="password" required class="input" />
</div>
</div>
<div class="field">
<altcha-widget challengeurl="https://api.slopfarmer.jack-case.pro/altcha-challenge"></altcha-widget>
</div>
<div class="field">
<button id="signup-button" class="button is-primary">sign up</button>
</div>
</form>
<h2></h2>
</div>
<div id="login" style="display:none" class="box">
<h1 class="title">Log In</h1>
<form id="login-form">
<div class="field">
<label for="email" id="username" class="label">E-Mail</label>
<div class="control">
<input type="text" name="username" required class="input" />
</div>
</div>
<div class="field">
<label for="password" id="password" class="label">Password</label>
<div class="control">
<input type="password" name="password" required class="input" />
</div>
</div>
<div class="field">
<button id="login-button" class="button is-primary">log in</button>
</div>
</form>
<h2 style="visibility: collapse;" id="login-status">You're logged in.</h2>
</div>
<div id="report" style="display: none" class="block">
<button id="report-button" class="button is-primary">Report this page</button>
<h2></h2>
</div>
</div>
</body>

View File

@@ -1,3 +1,4 @@
import { getTextOfJSDocComment } from "../node_modules/typescript/lib/typescript.js"
import { API_URL, send_message_to_background } from "./common.js"
let popup_state: PopupState = null
@@ -10,19 +11,45 @@ class PopupState {
page_elements: Map<string, HTMLElement>
constructor(logged_in: boolean, page_sections: Map<string, HTMLElement>, visible_section: string, page_elements: Map<string, HTMLElement>) {
visible_logged_in: Array<HTMLElement>
visible_logged_out: Array<HTMLElement>
constructor(logged_in: boolean, page_sections: Map<string, HTMLElement>, visible_section: string, page_elements: Map<string, HTMLElement>, visible_logged_in: Array<HTMLElement>, visible_logged_out: Array<HTMLElement>) {
this.logged_in = logged_in
this.page_sections = page_sections
this.visible_section = visible_section
this.set_visible_section(logged_in ? "report" : "signup")
this.page_elements = page_elements
this.visible_logged_in = visible_logged_in
this.visible_logged_out = visible_logged_out
}
update_login_visibility() {
this.visible_logged_in.forEach((element) => {
element.style.display = this.logged_in ? "block" : "none"
})
this.visible_logged_out.forEach((element) => {
element.style.display = this.logged_in ? "none" : "block"
})
}
set_visible_section(section_id: string) {
this.visible_section = section_id
switch (section_id) {
case "signup":
this.page_elements.get("signup_button").setAttribute("class", "is-active")
this.page_elements.get("login_button").setAttribute("class", "")
break
case "login":
this.page_elements.get("login_button").setAttribute("class", "is-active")
this.page_elements.get("signup_button").setAttribute("class", "")
break
}
this.page_sections.forEach((element, id) => {
element.style.visibility = id === section_id ? "visible" : "collapse"
element.style.display = id === section_id ? "block" : "none"
})
this.update_login_visibility()
}
}
@@ -47,6 +74,8 @@ async function submit_login_form() {
const status_el = document.getElementById("login-status")
status_el.setAttribute("style", "visibility: visible;")
popup_state.logged_in = true
popup_state.set_visible_section("report")
}
else {
@@ -70,6 +99,12 @@ async function submit_signup_form() {
}
}
async function logout() {
const response = await send_message_to_background({type: "logout"})
popup_state.logged_in = false
popup_state.set_visible_section("login")
}
async function check_login(): Promise<boolean> {
const response = await send_message_to_background({type: "islogged"})
return response.logged_in
@@ -85,11 +120,12 @@ async function initialize_popup() {
const login_section = document.getElementById("login")
const report_section = document.getElementById("report")
const signup_button = document.getElementById("signup-select") as HTMLButtonElement
const signup_button = document.getElementById("signup-tab")
const signup_status = signup_section.querySelector("h2")
const login_button = document.getElementById("login-select") as HTMLButtonElement
const login_button = document.getElementById("login-tab")
const report_button = document.getElementById("report-button") as HTMLButtonElement
const report_status = report_section.querySelector("h2")
const logout_button = document.getElementById("logout-button")
const page_sections = new Map()
page_sections.set("signup", signup_section)
@@ -103,11 +139,16 @@ async function initialize_popup() {
page_elements.set("signup_status", signup_status)
page_elements.set("report_button", report_button)
page_elements.set("report_status", report_status)
page_elements.set("signup_button", signup_button)
page_elements.set("login_button", login_button)
const logged_in_items = Array.from(document.querySelectorAll(".logged-in")) as Array<HTMLElement>
const logged_out_items = Array.from(document.querySelectorAll(".not-logged-in")) as Array<HTMLElement>
const logged_in = await check_login()
popup_state = new PopupState(logged_in, page_sections, "signup", page_elements)
popup_state = new PopupState(logged_in, page_sections, "signup", page_elements, logged_in_items, logged_out_items)
popup_state.set_visible_section(logged_in ? "report" : "signup")
login_form.addEventListener("submit", (event) => { event.preventDefault(); submit_login_form() })
signup_form.addEventListener("submit", (event) => { event.preventDefault(); submit_signup_form() })
@@ -119,6 +160,9 @@ async function initialize_popup() {
popup_state.page_elements.get("report_status").textContent = "report accepted"
setTimeout(() => { window.close() }, 1000)
})
logout_button.addEventListener("click", async (event) => {
logout()
})
}
addEventListener("DOMContentLoaded", (event) => {

View File

@@ -225,6 +225,11 @@ function message_listener(message: any, sender: any, send_response: Function): P
return new Promise((resolve, reject) => { resolve(response) })
break
case "logout":
localStorage.removeItem("accessToken")
return new Promise((resolve, reject) => { resolve(true) })
break
case "report":
return new Promise((resolve, reject) => {
browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {

21
styles/bulma/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2023 Jeremy Thomas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

3
styles/bulma/bulma.min.css vendored Normal file

File diff suppressed because one or more lines are too long