diff --git a/package.json b/package.json index 533185c..5daa1a3 100644 --- a/package.json +++ b/package.json @@ -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" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 240e68b..234ac4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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==} diff --git a/src/entries/contentScript/classes/Board.ts b/src/entries/contentScript/classes/Board.ts deleted file mode 100644 index 3fef0f1..0000000 --- a/src/entries/contentScript/classes/Board.ts +++ /dev/null @@ -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 diff --git a/src/entries/contentScript/classes/Post.ts b/src/entries/contentScript/classes/Post.ts deleted file mode 100644 index 46a89cf..0000000 --- a/src/entries/contentScript/classes/Post.ts +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/src/entries/contentScript/classes/Thread.ts b/src/entries/contentScript/classes/Thread.ts deleted file mode 100644 index 57e1745..0000000 --- a/src/entries/contentScript/classes/Thread.ts +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/src/entries/contentScript/image.ts b/src/entries/contentScript/image.ts index ae59aef..52513ee 100644 --- a/src/entries/contentScript/image.ts +++ b/src/entries/contentScript/image.ts @@ -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 = $("") .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) => { diff --git a/src/entries/contentScript/primary/App.css b/src/entries/contentScript/primary/App.css deleted file mode 100644 index 262422e..0000000 --- a/src/entries/contentScript/primary/App.css +++ /dev/null @@ -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; -} diff --git a/src/entries/contentScript/primary/App.tsx b/src/entries/contentScript/primary/App.tsx index 1446a8b..c64cfb2 100644 --- a/src/entries/contentScript/primary/App.tsx +++ b/src/entries/contentScript/primary/App.tsx @@ -1,13 +1,14 @@ import React from "react" -import Catalog from "./Catalog" -import Header from "./Header" function App() { return (<> -
- +
+

+ Its over. +

+
) } diff --git a/src/entries/contentScript/primary/Catalog.tsx b/src/entries/contentScript/primary/Catalog.tsx deleted file mode 100644 index 0e6a3ab..0000000 --- a/src/entries/contentScript/primary/Catalog.tsx +++ /dev/null @@ -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 ( -
-
-

{catalogText}

-
-
- ) -} - -export default Catalog \ No newline at end of file diff --git a/src/entries/contentScript/primary/Header.tsx b/src/entries/contentScript/primary/Header.tsx index 8ec136e..076fd79 100644 --- a/src/entries/contentScript/primary/Header.tsx +++ b/src/entries/contentScript/primary/Header.tsx @@ -1,14 +1,21 @@ import React, { useState } from "react" import SettingsPopup from "./SettingsPopup" +import $ from "jquery" interface HeaderBarProps { board: string; } -const Header: React.FC = ({ board }) => { - const indexUrl = `https://boards.4chan.org/${board}/` - const catalogUrl = `https://boards.4chan.org/${board}/catalog` +const Header: React.FC = () => { + const indexUrl = "https://boards.4chan.org/pol/" + const catalogUrl = "https://boards.4chan.org/pol/catalog" const [settingsVisible, setSettingsVisible] = useState(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 = ({ board }) => { {settingsVisible && (
- +
)} diff --git a/src/entries/contentScript/primary/SettingsPopup.tsx b/src/entries/contentScript/primary/SettingsPopup.tsx index 27d676c..71619c5 100644 --- a/src/entries/contentScript/primary/SettingsPopup.tsx +++ b/src/entries/contentScript/primary/SettingsPopup.tsx @@ -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(defaultConfig) +const SettingsPopup: React.FC = ({ onClose }) => { const [activeTab, setActiveTab] = useState("Main") const handleImageHoverChange = (e: React.ChangeEvent) => { - 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 (
-

Settings

- - - +

Settings

+