mirror of
https://github.com/LalleSX/4chan-XZ.git
synced 2026-01-30 09:48:12 +01:00
Header etc
This commit is contained in:
parent
4cbb5df7c6
commit
2fe2cb2c5c
@ -41,6 +41,8 @@
|
||||
"imageboard": "^0.6.25",
|
||||
"jquery": "^3.6.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"webextension-polyfill": "^0.10.0"
|
||||
}
|
||||
|
||||
75
pnpm-lock.yaml
generated
75
pnpm-lock.yaml
generated
@ -28,6 +28,12 @@ dependencies:
|
||||
react:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0
|
||||
react-dnd:
|
||||
specifier: ^16.0.1
|
||||
version: 16.0.1(@types/react@18.0.28)(react@18.2.0)
|
||||
react-dnd-html5-backend:
|
||||
specifier: ^16.0.1
|
||||
version: 16.0.1
|
||||
react-dom:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
@ -289,7 +295,6 @@ packages:
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
regenerator-runtime: 0.13.11
|
||||
dev: true
|
||||
|
||||
/@babel/template@7.20.7:
|
||||
resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==}
|
||||
@ -698,6 +703,18 @@ packages:
|
||||
config-chain: 1.1.13
|
||||
dev: true
|
||||
|
||||
/@react-dnd/asap@5.0.2:
|
||||
resolution: {integrity: sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==}
|
||||
dev: false
|
||||
|
||||
/@react-dnd/invariant@4.0.2:
|
||||
resolution: {integrity: sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==}
|
||||
dev: false
|
||||
|
||||
/@react-dnd/shallowequal@4.0.2:
|
||||
resolution: {integrity: sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==}
|
||||
dev: false
|
||||
|
||||
/@samrum/vite-plugin-web-extension@4.0.0(vite@4.3.1):
|
||||
resolution: {integrity: sha512-j0wM6bZn9Pk2KFa8QAeUJwQOAyAvrtMZRjL88vZ3ecmRuUuheuj6mByDrPLm6EBzls1+d7Q4aUoH7z0sYKe97g==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
@ -786,7 +803,6 @@ packages:
|
||||
|
||||
/@types/prop-types@15.7.5:
|
||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||
dev: true
|
||||
|
||||
/@types/react-dom@18.0.11:
|
||||
resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==}
|
||||
@ -800,11 +816,9 @@ packages:
|
||||
'@types/prop-types': 15.7.5
|
||||
'@types/scheduler': 0.16.3
|
||||
csstype: 3.1.2
|
||||
dev: true
|
||||
|
||||
/@types/scheduler@0.16.3:
|
||||
resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==}
|
||||
dev: true
|
||||
|
||||
/@types/semver@7.5.0:
|
||||
resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==}
|
||||
@ -1648,7 +1662,6 @@ packages:
|
||||
|
||||
/csstype@3.1.2:
|
||||
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
||||
dev: true
|
||||
|
||||
/dashdash@1.14.1:
|
||||
resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
|
||||
@ -1772,6 +1785,14 @@ packages:
|
||||
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
||||
dev: true
|
||||
|
||||
/dnd-core@16.0.1:
|
||||
resolution: {integrity: sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==}
|
||||
dependencies:
|
||||
'@react-dnd/asap': 5.0.2
|
||||
'@react-dnd/invariant': 4.0.2
|
||||
redux: 4.2.1
|
||||
dev: false
|
||||
|
||||
/doctrine@2.1.0:
|
||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -2836,6 +2857,12 @@ packages:
|
||||
dependencies:
|
||||
function-bind: 1.1.1
|
||||
|
||||
/hoist-non-react-statics@3.3.2:
|
||||
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
||||
dependencies:
|
||||
react-is: 16.13.1
|
||||
dev: false
|
||||
|
||||
/html-document-parser@1.1.1:
|
||||
resolution: {integrity: sha512-nbwGhL9zpmrtTXVdbRfmmxKJ2Vxd6ULOggjtPfaRFwWr67fM181XY0CvWLx/DqQR1BrJD93K/qJmp5ReSq4xHQ==}
|
||||
dependencies:
|
||||
@ -4073,6 +4100,36 @@ packages:
|
||||
strip-json-comments: 2.0.1
|
||||
dev: true
|
||||
|
||||
/react-dnd-html5-backend@16.0.1:
|
||||
resolution: {integrity: sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==}
|
||||
dependencies:
|
||||
dnd-core: 16.0.1
|
||||
dev: false
|
||||
|
||||
/react-dnd@16.0.1(@types/react@18.0.28)(react@18.2.0):
|
||||
resolution: {integrity: sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==}
|
||||
peerDependencies:
|
||||
'@types/hoist-non-react-statics': '>= 3.3.1'
|
||||
'@types/node': '>= 12'
|
||||
'@types/react': '>= 16'
|
||||
react: '>= 16.14'
|
||||
peerDependenciesMeta:
|
||||
'@types/hoist-non-react-statics':
|
||||
optional: true
|
||||
'@types/node':
|
||||
optional: true
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@react-dnd/invariant': 4.0.2
|
||||
'@react-dnd/shallowequal': 4.0.2
|
||||
'@types/react': 18.0.28
|
||||
dnd-core: 16.0.1
|
||||
fast-deep-equal: 3.1.3
|
||||
hoist-non-react-statics: 3.3.2
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-dom@18.2.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
||||
peerDependencies:
|
||||
@ -4085,7 +4142,6 @@ packages:
|
||||
|
||||
/react-is@16.13.1:
|
||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||
dev: true
|
||||
|
||||
/react-refresh@0.14.0:
|
||||
resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
|
||||
@ -4139,9 +4195,14 @@ packages:
|
||||
engines: {node: '>= 12.13.0'}
|
||||
dev: true
|
||||
|
||||
/redux@4.2.1:
|
||||
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.21.0
|
||||
dev: false
|
||||
|
||||
/regenerator-runtime@0.13.11:
|
||||
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
||||
dev: true
|
||||
|
||||
/regexp.prototype.flags@1.5.0:
|
||||
resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
import Post from "./Post"
|
||||
|
||||
class Board {
|
||||
boardName: string
|
||||
apiUrl: string
|
||||
posts: Post[]
|
||||
|
||||
constructor(boardName: string) {
|
||||
this.boardName = boardName
|
||||
this.apiUrl = `https://a.4cdn.org/${boardName}/threads.json`
|
||||
this.posts = []
|
||||
}
|
||||
|
||||
async fetchThreads() {
|
||||
try {
|
||||
const response = await fetch(this.apiUrl)
|
||||
const data = await response.json()
|
||||
console.log(data)
|
||||
// Process data and populate this.posts
|
||||
} catch (error) {
|
||||
console.error("Error fetching threads:", error)
|
||||
}
|
||||
}
|
||||
// Add more methods to interact with the 4chan API and manage the data
|
||||
}
|
||||
|
||||
export default Board
|
||||
@ -1,13 +0,0 @@
|
||||
export default class Post {
|
||||
postId: number
|
||||
author: string
|
||||
content: string
|
||||
timestamp: Date
|
||||
|
||||
constructor(postId: number, author: string, content: string, timestamp: Date) {
|
||||
this.postId = postId
|
||||
this.author = author
|
||||
this.content = content
|
||||
this.timestamp = timestamp
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
import Post from "./Post"
|
||||
|
||||
|
||||
export default class Thread {
|
||||
threadId: number
|
||||
title: string
|
||||
opPost: Post
|
||||
replies: Post[]
|
||||
|
||||
constructor(threadId: number, title: string, opPost: Post) {
|
||||
this.threadId = threadId
|
||||
this.title = title
|
||||
this.opPost = opPost
|
||||
this.replies = []
|
||||
}
|
||||
|
||||
addReply(reply: Post): void {
|
||||
this.replies.push(reply)
|
||||
}
|
||||
|
||||
getReplyCount(): number {
|
||||
return this.replies.length
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,20 @@
|
||||
import $ from "jquery"
|
||||
import { Config } from "../options/Conf"
|
||||
// This function initializes the image hovering functionality
|
||||
|
||||
/**
|
||||
|
||||
Initializes the image hovering functionality for 4chan.
|
||||
*/
|
||||
export function initImageHovering(): void {
|
||||
// If image hovering is disabled, return early
|
||||
if (Config.main.ImageHover === false) { return }
|
||||
// Get the user's configuration
|
||||
const config = Config.main.ImageHover
|
||||
|
||||
// If the user has disabled image hovering, do nothing
|
||||
if (!config.valueOf()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Find all thumbnail images on the page
|
||||
const thumbnails = $("a.fileThumb")
|
||||
|
||||
@ -11,7 +22,6 @@ export function initImageHovering(): void {
|
||||
thumbnails.each(function () {
|
||||
const thumbnail = $(this)
|
||||
const imageUrl = thumbnail.attr("href") as string
|
||||
|
||||
// Create a new image element to be displayed on hover
|
||||
const hoverImage = $("<img>")
|
||||
.attr("src", imageUrl)
|
||||
@ -23,12 +33,13 @@ export function initImageHovering(): void {
|
||||
.appendTo("body")
|
||||
|
||||
// Show the image on mouseover and hide it on mouseout
|
||||
thumbnail.on("mouseover", () => {
|
||||
hoverImage.show()
|
||||
})
|
||||
thumbnail.on("mouseout", () => {
|
||||
hoverImage.hide()
|
||||
})
|
||||
thumbnail
|
||||
.on("mouseover", () => {
|
||||
hoverImage.show()
|
||||
})
|
||||
.on("mouseout", () => {
|
||||
hoverImage.hide()
|
||||
})
|
||||
|
||||
// Update the hover image position based on the mouse cursor
|
||||
thumbnail.on("mousemove", (event) => {
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
.logo {
|
||||
z-index: 99999;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 10px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: 4px solid #c72a21;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
}
|
||||
@ -1,13 +1,14 @@
|
||||
import React from "react"
|
||||
import Catalog from "./Catalog"
|
||||
import Header from "./Header"
|
||||
|
||||
|
||||
function App() {
|
||||
|
||||
return (<>
|
||||
<Header board="g" />
|
||||
<Catalog />
|
||||
<div>
|
||||
<p>
|
||||
Its over.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
import React from "react"
|
||||
import $ from "jquery"
|
||||
import Board from "../classes/Board"
|
||||
|
||||
const Catalog = () => {
|
||||
const catalogText = "Hello world"
|
||||
new Board("g")
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<div className="flex flex-row items-center justify-center">
|
||||
<p className="text-black font-bold">{catalogText}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Catalog
|
||||
@ -1,14 +1,21 @@
|
||||
import React, { useState } from "react"
|
||||
import SettingsPopup from "./SettingsPopup"
|
||||
import $ from "jquery"
|
||||
|
||||
interface HeaderBarProps {
|
||||
board: string;
|
||||
}
|
||||
|
||||
const Header: React.FC<HeaderBarProps> = ({ board }) => {
|
||||
const indexUrl = `https://boards.4chan.org/${board}/`
|
||||
const catalogUrl = `https://boards.4chan.org/${board}/catalog`
|
||||
const Header: React.FC<HeaderBarProps> = () => {
|
||||
const indexUrl = "https://boards.4chan.org/pol/"
|
||||
const catalogUrl = "https://boards.4chan.org/pol/catalog"
|
||||
const [settingsVisible, setSettingsVisible] = useState<boolean>(false)
|
||||
// Remove the default header
|
||||
$("#boardNavDesktop").remove()
|
||||
$(".danbo-slot").remove()
|
||||
$("h4").remove()
|
||||
$(".abovePostForm").remove()
|
||||
$(".boardList").remove()
|
||||
|
||||
const toggleSettingsPopup = () => {
|
||||
setSettingsVisible(!settingsVisible)
|
||||
@ -32,7 +39,7 @@ const Header: React.FC<HeaderBarProps> = ({ board }) => {
|
||||
</button>
|
||||
{settingsVisible && (
|
||||
<div className="absolute right-0 mt-2">
|
||||
<SettingsPopup />
|
||||
<SettingsPopup onClose={toggleSettingsPopup} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -1,54 +1,27 @@
|
||||
import React, { useState } from "react"
|
||||
import Header from "./Header"
|
||||
import { Config } from "~/entries/options/Conf"
|
||||
|
||||
interface ConfigProps {
|
||||
main: {
|
||||
ImageHover: boolean;
|
||||
};
|
||||
|
||||
interface SettingsPopupProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const defaultConfig: ConfigProps = {
|
||||
main: {
|
||||
ImageHover: true,
|
||||
},
|
||||
}
|
||||
|
||||
const SettingsPopup: React.FC = () => {
|
||||
const [config, setConfig] = useState<ConfigProps>(defaultConfig)
|
||||
const SettingsPopup: React.FC<SettingsPopupProps> = ({ onClose }) => {
|
||||
const [activeTab, setActiveTab] = useState<string>("Main")
|
||||
|
||||
const handleImageHoverChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setConfig({ ...config, main: { ...config.main, ImageHover: e.target.checked } })
|
||||
const newConfig = { ...Config }
|
||||
newConfig.main.ImageHover = e.target.checked
|
||||
chrome.storage.sync.set({ config: newConfig })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 left-0 w-full h-full flex justify-center items-center">
|
||||
<div className="bg-white p-4 rounded-lg shadow-md">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h1 className="text-xl font-semibold">Settings</h1>
|
||||
|
||||
<button
|
||||
className="text-red-500 hover:text-red-600"
|
||||
onClick={() => {
|
||||
chrome.storage.sync.set({ config })
|
||||
window.location.reload()
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<h2 className="text-xl font-semibold">Settings</h2>
|
||||
<button onClick={onClose}>X</button>
|
||||
</div>
|
||||
<div className="flex mb-4">
|
||||
<button
|
||||
@ -72,7 +45,7 @@ const SettingsPopup: React.FC = () => {
|
||||
id="image-hover"
|
||||
type="checkbox"
|
||||
className="mr-2"
|
||||
checked={config.main.ImageHover}
|
||||
checked={Config.main.ImageHover}
|
||||
onChange={handleImageHoverChange}
|
||||
/>
|
||||
Image Hover
|
||||
|
||||
@ -4,34 +4,22 @@ import ReactDOM from "react-dom/client"
|
||||
import renderContent from "../renderContent"
|
||||
import App from "./App"
|
||||
import "../../../index.css"
|
||||
import Post from "../classes/Post"
|
||||
import Thread from "../classes/Thread"
|
||||
import { initImageHovering } from "../image"
|
||||
import $ from "jquery"
|
||||
import Header from "./Header"
|
||||
|
||||
renderContent(import.meta.PLUGIN_WEB_EXT_CHUNK_CSS_PATHS, (appRoot) => {
|
||||
ReactDOM.createRoot(appRoot).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<Header board="pol" />
|
||||
</React.StrictMode>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
// Usage example:
|
||||
|
||||
const opPost = new Post(1, "Anonymous", "Hello, this is the first post in the thread!", new Date())
|
||||
const thread = new Thread(12345, "Example Thread", opPost)
|
||||
|
||||
const reply1 = new Post(2, "Anonymous", "Nice thread!", new Date())
|
||||
thread.addReply(reply1)
|
||||
|
||||
console.log("Thread ID:", thread.threadId)
|
||||
console.log("Thread Title:", thread.title)
|
||||
console.log("Number of Replies:", thread.getReplyCount())
|
||||
|
||||
// Initialize the image hovering functionality once the document is ready
|
||||
$(document).ready(() => {
|
||||
console.log("Document is ready!")
|
||||
initImageHovering()
|
||||
initImageHovering()
|
||||
})
|
||||
@ -4,7 +4,7 @@ const sharedManifest = {
|
||||
content_scripts: [
|
||||
{
|
||||
js: ["src/entries/contentScript/primary/main.tsx"],
|
||||
matches: ["*://4chan.org/*", "*://boards.4chan.org/*, *://boards.4channel.org/*", "*://boards.4channel.org/*"],
|
||||
matches: ["*://4chan.org/*", "*://boards.4chan.org/*, *://boards.4chan.org/*", "*://boards.4channel.org/*"],
|
||||
},
|
||||
],
|
||||
icons: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user