mirror of
https://github.com/snachodog/tok-to-insta-follower-bridge.git
synced 2025-04-10 14:11:22 -06:00
✨ use vanjs
This commit is contained in:
parent
782b75c8fc
commit
d6bc1af255
17
package-lock.json
generated
17
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "sky-follower-bridge",
|
||||
"version": "0.1.3",
|
||||
"version": "0.2.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sky-follower-bridge",
|
||||
"version": "0.1.3",
|
||||
"version": "0.2.0",
|
||||
"dependencies": {
|
||||
"@atproto/api": "^0.6.4",
|
||||
"@plasmohq/messaging": "^0.5.0",
|
||||
@ -14,7 +14,8 @@
|
||||
"plasmo": "^0.82.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"ts-pattern": "^5.0.5"
|
||||
"ts-pattern": "^5.0.5",
|
||||
"vanjs-core": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@plasmohq/prettier-plugin-sort-imports": "4.0.1",
|
||||
@ -9536,6 +9537,11 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/vanjs-core": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vanjs-core/-/vanjs-core-1.0.2.tgz",
|
||||
"integrity": "sha512-c/ding4r+NRMobYJTLjVYyrqee51Zi1Er+8k1QV1vTZW4+e30/728DQOQh8yQc2VdZSrNJHYRWhW02C4NoiJgw=="
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz",
|
||||
@ -15806,6 +15812,11 @@
|
||||
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
|
||||
"integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg=="
|
||||
},
|
||||
"vanjs-core": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vanjs-core/-/vanjs-core-1.0.2.tgz",
|
||||
"integrity": "sha512-c/ding4r+NRMobYJTLjVYyrqee51Zi1Er+8k1QV1vTZW4+e30/728DQOQh8yQc2VdZSrNJHYRWhW02C4NoiJgw=="
|
||||
},
|
||||
"vue": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz",
|
||||
|
@ -18,7 +18,8 @@
|
||||
"plasmo": "^0.82.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"ts-pattern": "^5.0.5"
|
||||
"ts-pattern": "^5.0.5",
|
||||
"vanjs-core": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@plasmohq/prettier-plugin-sort-imports": "4.0.1",
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { BskyClient, BskyLoginParams } from "./lib/bskyClient";
|
||||
import { BskyClient, type BskyLoginParams } from "./lib/bskyClient";
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import { MESSAGE_NAMES, VIEWER_STATE } from "~lib/constants";
|
||||
import "./style.content.css"
|
||||
import { initialize, searchBskyUsers } from '~lib/searchAndInsertBskyUsers';
|
||||
import { searchBskyUsers } from '~lib/searchAndInsertBskyUsers';
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://twitter.com/*", "https://x.com/*"],
|
||||
@ -54,7 +54,6 @@ const searchAndShowBskyUsers = async ({
|
||||
|
||||
chrome.runtime.onMessage.addListener((message, _, sendResponse) => {
|
||||
if (Object.values(MESSAGE_NAMES).includes(message.name)) {
|
||||
initialize()
|
||||
searchAndShowBskyUsers({
|
||||
identifier: message.body.userId,
|
||||
password: message.body.password,
|
||||
@ -64,6 +63,7 @@ chrome.runtime.onMessage.addListener((message, _, sendResponse) => {
|
||||
sendResponse({ hasError: false })
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
sendResponse({ hasError: true, message: e.toString() })
|
||||
});
|
||||
return true
|
||||
|
125
src/lib/components/BskyUserCell.ts
Normal file
125
src/lib/components/BskyUserCell.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import type { ProfileView, ViewerState } from "@atproto/api/dist/client/types/app/bsky/actor/defs"
|
||||
import van from 'vanjs-core'
|
||||
|
||||
const { a, div, p, img, button } = van.tags
|
||||
|
||||
export type UserCellBtnLabel = {
|
||||
add: string,
|
||||
remove: string,
|
||||
progressive: string,
|
||||
}
|
||||
|
||||
const ActionButton = ({ statusKey, profile, btnLabel, addAction, removeAction }: {
|
||||
profile: ProfileView,
|
||||
statusKey: keyof ViewerState,
|
||||
btnLabel: UserCellBtnLabel,
|
||||
addAction: () => Promise<void>,
|
||||
removeAction: () => Promise<void>
|
||||
}) => {
|
||||
const label = van.state(`${profile.viewer[statusKey] ? btnLabel.progressive : btnLabel.add} on Bluesky`)
|
||||
|
||||
const isStateOfBeing = van.state(profile.viewer[statusKey])
|
||||
const isProcessing = van.state(false)
|
||||
const isJustApplied = van.state(false)
|
||||
|
||||
const beingClass = van.derive(() => isStateOfBeing.val ? "action-button__being" : "")
|
||||
const processingClass = van.derive(() => isProcessing.val ? "action-button__processing" : "")
|
||||
const justAppliedClass = van.derive(() => isJustApplied.val ? "action-button__just-applied" : "")
|
||||
|
||||
const onClick = async () => {
|
||||
if (isProcessing.val) return
|
||||
isProcessing.val = true
|
||||
label.val = "Processing..."
|
||||
|
||||
if (isStateOfBeing.val) {
|
||||
await removeAction()
|
||||
label.val = `${btnLabel.add} on Bluesky`
|
||||
isStateOfBeing.val = false
|
||||
} else {
|
||||
await addAction()
|
||||
label.val = `${btnLabel.progressive} on Bluesky`
|
||||
isStateOfBeing.val = true
|
||||
isJustApplied.val = true
|
||||
}
|
||||
|
||||
isProcessing.val = false
|
||||
}
|
||||
|
||||
const onMouseover = () => {
|
||||
if(
|
||||
isProcessing.val ||
|
||||
isJustApplied.val ||
|
||||
!isStateOfBeing.val
|
||||
) return
|
||||
|
||||
label.val = `${btnLabel.remove} on Bluesky`
|
||||
}
|
||||
|
||||
const onMouseout = () => {
|
||||
if (isJustApplied.val) {
|
||||
isJustApplied.val = false
|
||||
}
|
||||
if(!isStateOfBeing.val) return
|
||||
|
||||
label.val = `${btnLabel.progressive} on Bluesky`
|
||||
}
|
||||
|
||||
return () => button({
|
||||
class: `action-button ${beingClass.val} ${processingClass.val} ${justAppliedClass.val}`,
|
||||
onclick: onClick,
|
||||
onmouseover: onMouseover,
|
||||
onmouseout: onMouseout,
|
||||
},
|
||||
label.val,
|
||||
)
|
||||
}
|
||||
|
||||
const Avatar = ({ avatar }: { avatar?: string }) => {
|
||||
return avatar ? img({ src: avatar, width: "40" }) : div({ class: "no-avatar" })
|
||||
}
|
||||
|
||||
export const BskyUserCell = ({
|
||||
profile,
|
||||
statusKey,
|
||||
btnLabel,
|
||||
addAction,
|
||||
removeAction,
|
||||
}: {
|
||||
profile: ProfileView,
|
||||
statusKey: keyof ViewerState,
|
||||
btnLabel: UserCellBtnLabel,
|
||||
addAction: () => Promise<void>,
|
||||
removeAction: () => Promise<void>
|
||||
}) => {
|
||||
return div({ class: "bsky-user-content" },
|
||||
div({ class: "icon-section"},
|
||||
a({ href: `https://bsky.app/profile/${profile.handle}`, target: "_blank", rel: "noopener" },
|
||||
Avatar({ avatar: profile.avatar }),
|
||||
),
|
||||
),
|
||||
div({ class: "content" },
|
||||
div({ class: "name-and-controller" },
|
||||
div(
|
||||
p({ class: "display-name" },
|
||||
a({ href: `https://bsky.app/profile/${profile.handle}`, target: "_blank", rel: "noopener" },
|
||||
profile.displayName ?? profile.handle,
|
||||
),
|
||||
),
|
||||
p({ class: "handle" },
|
||||
`@${profile.handle}`,
|
||||
),
|
||||
),
|
||||
div(
|
||||
ActionButton({
|
||||
profile,
|
||||
statusKey,
|
||||
btnLabel,
|
||||
addAction,
|
||||
removeAction,
|
||||
})
|
||||
),
|
||||
),
|
||||
profile.description ? p({ class: "description" }, profile.description) : "",
|
||||
),
|
||||
)
|
||||
}
|
29
src/lib/components/NotFoundCell.ts
Normal file
29
src/lib/components/NotFoundCell.ts
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
import van from "vanjs-core"
|
||||
|
||||
const { div, p } = van.tags
|
||||
const { svg, path } = van.tagsNS("http://www.w3.org/2000/svg")
|
||||
|
||||
const WarningIcon = () => svg(
|
||||
{
|
||||
fill: "none",
|
||||
"stroke-width": "1.5",
|
||||
stroke: "currentColor",
|
||||
class: "w-6 h-6",
|
||||
viewBox: "0 0 24 24"
|
||||
},
|
||||
path({
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
|
||||
}),
|
||||
)
|
||||
|
||||
export const NotFoundCell = () => div({ class: "bsky-user-content bsky-user-content__not-found" },
|
||||
WarningIcon(),
|
||||
p({
|
||||
class: "not-found"
|
||||
},
|
||||
"No similar users found."
|
||||
)
|
||||
)
|
19
src/lib/components/ReloadBtn.ts
Normal file
19
src/lib/components/ReloadBtn.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import van from "vanjs-core"
|
||||
|
||||
const { button, div } = van.tags
|
||||
|
||||
export const ReloadButton = ({clickAction}: {clickAction: () => void}) => {
|
||||
const deleted = van.state(false)
|
||||
|
||||
return () => deleted.val ? null : div({ class: "bsky-reload-btn-wrapper" },
|
||||
button(
|
||||
{
|
||||
class: "bsky-reload-btn",
|
||||
onclick: () => {
|
||||
clickAction()
|
||||
deleted.val = true
|
||||
}
|
||||
},
|
||||
"Find More"
|
||||
))
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
import type { ProfileView, ViewerState } from "@atproto/api/dist/client/types/app/bsky/actor/defs"
|
||||
|
||||
export type UserCellBtnLabel = {
|
||||
add: string,
|
||||
remove: string,
|
||||
progressive: string,
|
||||
}
|
||||
import van from "vanjs-core"
|
||||
import { ReloadButton } from "./components/ReloadBtn"
|
||||
import { NotFoundCell } from "./components/NotFoundCell"
|
||||
import { BskyUserCell, type UserCellBtnLabel } from "./components/BskyUserCell"
|
||||
|
||||
export const getUserCells = ({ queryParam, filterInsertedElement }: { queryParam: string, filterInsertedElement: boolean }) => {
|
||||
const userCells = document.querySelectorAll(queryParam);
|
||||
@ -23,27 +21,7 @@ export const getUserCells = ({ queryParam, filterInsertedElement }: { queryParam
|
||||
|
||||
export const insertReloadEl = (clickAction: () => void) => {
|
||||
const lastInsertedEl = Array.from(document.querySelectorAll('.bsky-user-content')).at(-1)
|
||||
lastInsertedEl.insertAdjacentHTML('afterend', `
|
||||
<div class="bsky-reload-btn-wrapper">
|
||||
<button class="bsky-reload-btn">
|
||||
Find More
|
||||
</button>
|
||||
</div>
|
||||
`)
|
||||
|
||||
const reloadBtn = document.querySelector(".bsky-reload-btn") as HTMLElement
|
||||
reloadBtn.addEventListener("click", async (e) => {
|
||||
const target = e.target as HTMLButtonElement
|
||||
if (target.classList.contains('bsky-reload-btn__processing')) {
|
||||
return
|
||||
}
|
||||
await clickAction()
|
||||
})
|
||||
}
|
||||
|
||||
export const removeReloadElIfExists = () => {
|
||||
const reloadBtnWrapper = document.querySelector(".bsky-reload-btn-wrapper") as HTMLElement
|
||||
reloadBtnWrapper?.remove()
|
||||
van.add(lastInsertedEl.parentElement, ReloadButton({clickAction}))
|
||||
}
|
||||
|
||||
export const getAccountNameAndDisplayName = (userCell: Element) => {
|
||||
@ -53,111 +31,25 @@ export const getAccountNameAndDisplayName = (userCell: Element) => {
|
||||
return { twAccountName, twDisplayName }
|
||||
}
|
||||
|
||||
// TODO: vanjsを使ってdom操作を描き直したい
|
||||
export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, abortController, followAction, unfollowAction }: {
|
||||
export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, addAction, removeAction }: {
|
||||
dom: Element,
|
||||
profile: ProfileView,
|
||||
statusKey: keyof ViewerState,
|
||||
btnLabel: UserCellBtnLabel,
|
||||
abortController: AbortController,
|
||||
followAction: () => void,
|
||||
unfollowAction: () => void
|
||||
addAction: () => Promise<void>,
|
||||
removeAction: () => Promise<void>
|
||||
}) => {
|
||||
const avatarEl = profile.avatar ? `<img src="${profile.avatar}" width="48" />` : "<div class='no-avatar'></div>"
|
||||
const actionBtnEl = profile.viewer[statusKey] ? `<button class='follow-button follow-button__following'>${btnLabel.progressive} on Bluesky</button>` : `<button class='follow-button'>${btnLabel.add} on Bluesky</button>`
|
||||
dom.insertAdjacentHTML('afterend', `
|
||||
<div class="bsky-user-content">
|
||||
<div class="icon-section">
|
||||
<a href="https://bsky.app/profile/${profile.handle}" target="_blank" rel="noopener">
|
||||
${avatarEl}
|
||||
</a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="name-and-controller">
|
||||
<div>
|
||||
<p class="display-name"><a href="https://bsky.app/profile/${profile.handle}" target="_blank" rel="noopener">${profile.displayName ?? profile.handle}</a></p>
|
||||
<p class="handle">@${profile.handle}</p>
|
||||
</div>
|
||||
<div>
|
||||
${actionBtnEl}
|
||||
</div>
|
||||
</div>
|
||||
${profile.description ? `<p class="description">${profile.description}</p>` : ""}
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
const bskyUserContentDom = dom.nextElementSibling as Element
|
||||
|
||||
// register a click action
|
||||
bskyUserContentDom?.addEventListener('click', async (e) => {
|
||||
const target = e.target as Element
|
||||
const classList = target.classList
|
||||
|
||||
// follow action
|
||||
if (classList.contains('follow-button') && !classList.contains('follow-button__following')) {
|
||||
target.textContent = "processing..."
|
||||
target.classList.add('follow-button__processing')
|
||||
await followAction()
|
||||
target.textContent = `${btnLabel.progressive} on Bluesky`
|
||||
target.classList.remove('follow-button__processing')
|
||||
target.classList.add('follow-button__following')
|
||||
target.classList.add('follow-button__just-followed')
|
||||
return
|
||||
}
|
||||
|
||||
// unfollow action
|
||||
if (classList.contains('follow-button') && classList.contains('follow-button__following')) {
|
||||
target.textContent = "processing..."
|
||||
target.classList.add('follow-button__processing')
|
||||
await unfollowAction()
|
||||
target.textContent = `${btnLabel.add} on Bluesky`
|
||||
target.classList.remove('follow-button__processing')
|
||||
target.classList.remove('follow-button__following')
|
||||
return
|
||||
}
|
||||
}, {
|
||||
signal: abortController.signal
|
||||
})
|
||||
|
||||
bskyUserContentDom?.addEventListener('mouseover', async (e) => {
|
||||
const target = e.target as Element
|
||||
const classList = target.classList
|
||||
if (classList.contains('follow-button') && classList.contains('follow-button__following')) {
|
||||
target.textContent = `${btnLabel.remove} on Bluesky`
|
||||
}
|
||||
}, {
|
||||
signal: abortController.signal
|
||||
})
|
||||
bskyUserContentDom?.addEventListener('mouseout', async (e) => {
|
||||
const target = e.target as Element
|
||||
const classList = target.classList
|
||||
if (classList.contains('follow-button__just-followed')) {
|
||||
target.classList.remove('follow-button__just-followed')
|
||||
}
|
||||
if (classList.contains('follow-button') && classList.contains('follow-button__following')) {
|
||||
target.textContent = `${btnLabel.progressive} on Bluesky`
|
||||
}
|
||||
}, {
|
||||
signal: abortController.signal
|
||||
})
|
||||
van.add(dom.parentElement, BskyUserCell({
|
||||
profile,
|
||||
statusKey,
|
||||
btnLabel,
|
||||
addAction,
|
||||
removeAction,
|
||||
}))
|
||||
}
|
||||
|
||||
export const insertNotFoundEl = (dom: Element) => {
|
||||
dom.insertAdjacentHTML('afterend', `
|
||||
<div class="bsky-user-content bsky-user-content__not-found">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" /></svg>
|
||||
<p class="not-found">No similar users found.</p>
|
||||
</div>
|
||||
`)
|
||||
}
|
||||
|
||||
export const cleanBskyUserElements = () => {
|
||||
const bskyUserContent = document.querySelectorAll('.bsky-user-content');
|
||||
if (bskyUserContent.length > 0) {
|
||||
bskyUserContent.forEach((el) => {
|
||||
el.remove()
|
||||
})
|
||||
}
|
||||
van.add(dom.parentElement, NotFoundCell())
|
||||
}
|
||||
|
||||
export const isOutOfTopViewport = (el: Element) => {
|
||||
|
@ -1,22 +1,16 @@
|
||||
import { UserCellBtnLabel, isOutOfTopViewport } from './domHelpers';
|
||||
import { getAccountNameAndDisplayName, getUserCells, insertBskyProfileEl, insertNotFoundEl, insertReloadEl, removeReloadElIfExists } from "~lib/domHelpers";
|
||||
import { isOutOfTopViewport } from './domHelpers';
|
||||
import { getAccountNameAndDisplayName, getUserCells, insertBskyProfileEl, insertNotFoundEl, insertReloadEl } from "~lib/domHelpers";
|
||||
import { isSimilarUser } from "~lib/bskyHelpers";
|
||||
import { debugLog } from "~lib/utils";
|
||||
import type { BskyClient } from './bskyClient';
|
||||
import type { ViewerState } from '@atproto/api/dist/client/types/app/bsky/actor/defs';
|
||||
import type { UserCellBtnLabel } from './components/BskyUserCell';
|
||||
|
||||
|
||||
let abortController = new AbortController();
|
||||
|
||||
const notFoundUserCache = new Set<string>()
|
||||
|
||||
const followerUrlMap = new Map<string, string>()
|
||||
|
||||
export const initialize = async () => {
|
||||
abortController.abort()
|
||||
abortController = new AbortController()
|
||||
}
|
||||
|
||||
export const searchBskyUsers = async (
|
||||
{
|
||||
agent,
|
||||
@ -33,7 +27,6 @@ export const searchBskyUsers = async (
|
||||
addQuery: (arg: string) => Promise<any>,
|
||||
removeQuery: (arg: string) => Promise<any>,
|
||||
}) => {
|
||||
removeReloadElIfExists()
|
||||
|
||||
const userCells = getUserCells({
|
||||
queryParam: userCellQueryParam,
|
||||
@ -65,12 +58,11 @@ export const searchBskyUsers = async (
|
||||
profile: searchResultByAccountName,
|
||||
statusKey,
|
||||
btnLabel,
|
||||
abortController,
|
||||
followAction: async () => {
|
||||
addAction: async () => {
|
||||
const result = await addQuery(searchResultByAccountName.did);
|
||||
followerUrlMap.set(searchResultByAccountName.did, result.uri)
|
||||
},
|
||||
unfollowAction: async () => {
|
||||
removeAction: async () => {
|
||||
if (searchResultByAccountName?.viewer?.following) {
|
||||
await removeQuery(searchResultByAccountName?.viewer?.following);
|
||||
} else {
|
||||
@ -88,14 +80,13 @@ export const searchBskyUsers = async (
|
||||
insertBskyProfileEl({
|
||||
dom: userCell,
|
||||
profile: searchResultByDisplayName,
|
||||
abortController,
|
||||
statusKey,
|
||||
btnLabel,
|
||||
followAction: async () => {
|
||||
addAction: async () => {
|
||||
const result = await addQuery(searchResultByDisplayName.did);
|
||||
followerUrlMap.set(searchResultByDisplayName.did, result.uri)
|
||||
},
|
||||
unfollowAction: async () => {
|
||||
removeAction: async () => {
|
||||
if (searchResultByDisplayName?.viewer?.following) {
|
||||
await removeQuery(searchResultByDisplayName?.viewer?.following);
|
||||
} else {
|
||||
|
@ -27,13 +27,14 @@
|
||||
}
|
||||
.bsky-user-content .icon-section a{
|
||||
text-decoration: none;
|
||||
width: 40px;
|
||||
}
|
||||
.bsky-user-content .icon-section img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.bsky-user-content .icon-section .no-avatar {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: #ccc;
|
||||
border-radius: 50%;
|
||||
}
|
||||
@ -63,7 +64,7 @@
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.name-and-controller .follow-button {
|
||||
.name-and-controller .action-button {
|
||||
border: 1px solid #fff;
|
||||
padding: 6px 30px;
|
||||
font-size: 14px;
|
||||
@ -74,27 +75,27 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.name-and-controller .follow-button__following {
|
||||
.name-and-controller .action-button__being {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.name-and-controller .follow-button__following:hover {
|
||||
.name-and-controller .action-button__being:hover {
|
||||
background: rgba(255, 0, 0, 0.1);
|
||||
color: red;
|
||||
border: 1px solid red;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.name-and-controller .follow-button__following.follow-button__just-followed:hover {
|
||||
.name-and-controller .action-button__being.action-button__just-applied:hover {
|
||||
background: transparent !important;
|
||||
color: #fff !important;
|
||||
border: 1px solid #fff !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.name-and-controller .follow-button__processing {
|
||||
.name-and-controller .action-button__processing {
|
||||
background: rgb(255,255,255, 0.3) !important;
|
||||
color: #fff !important;
|
||||
border: 1px solid #fff !important;
|
||||
|
Loading…
x
Reference in New Issue
Block a user