added auto complete

This commit is contained in:
NanoAim
2025-07-10 11:04:05 +08:00
parent 252d33f001
commit 7f098d059d
3 changed files with 72 additions and 35 deletions

View File

@@ -174,7 +174,7 @@ export function useAutoComplete(
(x) => x._id !== "00000000000000000000000000", (x) => x._id !== "00000000000000000000000000",
); );
const matches = ( let matches = (
search.length > 0 search.length > 0
? users.filter((user) => ? users.filter((user) =>
user.username.toLowerCase().match(regex), user.username.toLowerCase().match(regex),
@@ -184,6 +184,13 @@ export function useAutoComplete(
.splice(0, 5) .splice(0, 5)
.filter((x) => typeof x !== "undefined"); .filter((x) => typeof x !== "undefined");
// Add @everyone if it matches the search and we're in a channel context
if (searchClues.users.type === "channel" &&
(search.length === 0 || "everyone".match(regex))) {
// Add a special "everyone" entry at the beginning
matches = [{ _id: "@everyone", username: "everyone" } as any, ...matches].slice(0, 5);
}
if (matches.length > 0) { if (matches.length > 0) {
const currentPosition = const currentPosition =
state.type !== "none" ? state.selected : 0; state.type !== "none" ? state.selected : 0;
@@ -256,13 +263,22 @@ export function useAutoComplete(
); );
} else if (state.type === "user") { } else if (state.type === "user") {
const selectedUser = state.matches[state.selected]; const selectedUser = state.matches[state.selected];
content.splice( // Handle @everyone special case
index, if (selectedUser._id === "@everyone") {
search.length + 1, content.splice(
"@", index,
selectedUser.username, search.length + 1,
" ", "@everyone ",
); );
} else {
content.splice(
index,
search.length + 1,
"@",
selectedUser.username,
" ",
);
}
} else { } else {
content.splice( content.splice(
index, index,
@@ -492,7 +508,7 @@ export default function AutoComplete({
{state.type === "user" && {state.type === "user" &&
state.matches.map((match, i) => ( state.matches.map((match, i) => (
<button <button
key={match} key={match._id || match}
className={i === state.selected ? "active" : ""} className={i === state.selected ? "active" : ""}
onMouseEnter={() => onMouseEnter={() =>
(i !== state.selected || !state.within) && (i !== state.selected || !state.within) &&
@@ -510,8 +526,28 @@ export default function AutoComplete({
}) })
} }
onClick={onClick}> onClick={onClick}>
<UserIcon size={24} target={match} status={true} /> {match._id === "@everyone" ? (
{match.username} <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span style={{
width: "24px",
height: "24px",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: "14px",
background: "var(--accent)",
color: "var(--accent-contrast)",
borderRadius: "50%",
fontWeight: "600"
}}>@</span>
<span>everyone</span>
</div>
) : (
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<UserIcon size={24} target={match} status={true} />
<span>{match.username}</span>
</div>
)}
</button> </button>
))} ))}
{state.type === "channel" && {state.type === "channel" &&

View File

@@ -48,12 +48,12 @@ export function RenderMention({ match }: CustomComponentProps) {
} }
const EveryoneMention = styled.span` const EveryoneMention = styled.span`
padding: 0 4px; padding: 0 6px;
flex-shrink: 0; flex-shrink: 0;
font-weight: 600; font-weight: 600;
cursor: default; cursor: pointer;
color: var(--foreground); color: var(--accent);
background: var(--secondary-background); background: var(--secondary-background);
border-radius: calc(var(--border-radius) * 2); border-radius: calc(var(--border-radius) * 2);

View File

@@ -22,25 +22,25 @@ export default observer(({ channel }: Props) => {
const currentRoles = const currentRoles =
channel.channel_type === "Group" channel.channel_type === "Group"
? ([ ? ([
{ {
id: "default", id: "default",
name: "Default", name: "Default",
permissions: permissions:
channel.permissions ?? channel.permissions ??
DEFAULT_PERMISSION_DIRECT_MESSAGE, DEFAULT_PERMISSION_DIRECT_MESSAGE,
}, },
] as RoleOrDefault[]) ] as RoleOrDefault[])
: (useRoles(channel.server! as any).map((role) => { : (useRoles(channel.server! as any).map((role) => {
return { return {
...role, ...role,
permissions: (role.id === "default" permissions: (role.id === "default"
? channel.default_permissions ? channel.default_permissions
: channel.role_permissions?.[role.id]) ?? { : channel.role_permissions?.[role.id]) ?? {
a: 0, a: 0,
d: 0, d: 0,
}, },
}; };
}) as RoleOrDefault[]); }) as RoleOrDefault[]);
return ( return (
<PermissionsLayout <PermissionsLayout
@@ -69,9 +69,9 @@ export default observer(({ channel }: Props) => {
typeof currentValue === "number" typeof currentValue === "number"
? currentValue ? currentValue
: ({ : ({
allow: currentValue.a, allow: currentValue.a,
deny: currentValue.d, deny: currentValue.d,
} as any), } as any),
); );
} }
@@ -109,6 +109,7 @@ export default observer(({ channel }: Props) => {
"UploadFiles", "UploadFiles",
"Masquerade", "Masquerade",
"React", "React",
"MentionEveryone",
"ManageChannel", "ManageChannel",
"ManagePermissions", "ManagePermissions",
]} ]}