mirror of
https://github.com/modrinth/code.git
synced 2026-08-31 03:55:59 +00:00
add keybinds to copy/open prod links (#7294)
This commit is contained in:
@@ -26,6 +26,17 @@ const copyProjectLink = async (
|
||||
}
|
||||
|
||||
await navigator.clipboard.writeText(url)
|
||||
return url
|
||||
}
|
||||
|
||||
function isOfficialModrinthHost(): boolean {
|
||||
const host = globalThis.location?.hostname
|
||||
return host === 'modrinth.com' || host === 'www.modrinth.com' || host === 'staging.modrinth.com'
|
||||
}
|
||||
|
||||
function isLocalhost(): boolean {
|
||||
const host = globalThis.location?.hostname
|
||||
return host === 'localhost' || host === '127.0.0.1' || host === '[::1]'
|
||||
}
|
||||
|
||||
const keybinds: { [id: string]: KeybindListener } = {
|
||||
@@ -71,31 +82,68 @@ const keybinds: { [id: string]: KeybindListener } = {
|
||||
keybind: 'Ctrl+Alt+C',
|
||||
description: 'Copy permalink',
|
||||
scope: 'project',
|
||||
action: async (ctx) => copyProjectLink(ctx.project, true, false, false),
|
||||
action: async (ctx) => {
|
||||
const url = await copyProjectLink(ctx.project, true, false, false)
|
||||
ctx.notifyCopied(url, 'Copied permalink to clipboard')
|
||||
},
|
||||
},
|
||||
'copy-relative-permalink': {
|
||||
keybind: 'Ctrl+Alt+R',
|
||||
description: 'Copy relative permalink',
|
||||
scope: 'project',
|
||||
action: async (ctx) => copyProjectLink(ctx.project, true, true, false),
|
||||
action: async (ctx) => {
|
||||
const url = await copyProjectLink(ctx.project, true, true, false)
|
||||
ctx.notifyCopied(url, 'Copied relative permalink to clipboard')
|
||||
},
|
||||
},
|
||||
'copy-page-permalink': {
|
||||
keybind: 'Shift+Ctrl+Alt+C',
|
||||
description: 'Copy permalink with page',
|
||||
scope: 'project',
|
||||
action: async (ctx) => copyProjectLink(ctx.project, true, false, true),
|
||||
action: async (ctx) => {
|
||||
const url = await copyProjectLink(ctx.project, true, false, true)
|
||||
ctx.notifyCopied(url, 'Copied permalink with page to clipboard')
|
||||
},
|
||||
},
|
||||
'copy-page-relative-permalink': {
|
||||
keybind: 'Shift+Ctrl+Alt+R',
|
||||
description: 'Copy relative permalink with page',
|
||||
scope: 'project',
|
||||
action: async (ctx) => copyProjectLink(ctx.project, true, true, true),
|
||||
action: async (ctx) => {
|
||||
const url = await copyProjectLink(ctx.project, true, true, true)
|
||||
ctx.notifyCopied(url, 'Copied relative permalink with page to clipboard')
|
||||
},
|
||||
},
|
||||
'copy-id': {
|
||||
keybind: 'Ctrl+Alt+D',
|
||||
description: 'Copy Project ID',
|
||||
scope: 'project',
|
||||
action: async (ctx) => await navigator.clipboard.writeText(ctx.project.id),
|
||||
action: async (ctx) => {
|
||||
await navigator.clipboard.writeText(ctx.project.id)
|
||||
ctx.notifyCopied(ctx.project.id, 'Copied Project ID to clipboard')
|
||||
},
|
||||
},
|
||||
'open-official-site': {
|
||||
keybind: 'Ctrl+Shift+P',
|
||||
description: 'Open current page on production/staging',
|
||||
scope: 'global',
|
||||
enabled: () => !isOfficialModrinthHost(),
|
||||
action: (ctx) => {
|
||||
globalThis.open(ctx.officialUrl, '_blank', 'noopener,noreferrer')
|
||||
},
|
||||
},
|
||||
'copy-official-site': {
|
||||
keybind: 'Ctrl+Shift+O',
|
||||
description: 'Copy production/staging URL (localhost only)',
|
||||
scope: 'global',
|
||||
enabled: () => isLocalhost(),
|
||||
action: async (ctx) => {
|
||||
await navigator.clipboard.writeText(ctx.officialUrl)
|
||||
const environment = ctx.officialUrl.startsWith('https://staging.modrinth.com')
|
||||
? 'staging'
|
||||
: 'production'
|
||||
ctx.notifyCopied(ctx.officialUrl, `Copied ${environment} URL to clipboard`)
|
||||
},
|
||||
},
|
||||
'approve-project': {
|
||||
keybind: 'Shift+Alt+A',
|
||||
|
||||
@@ -44,11 +44,12 @@ export class Keybinds {
|
||||
|
||||
handle(event: KeyboardEvent, ctx: ModerationContext): boolean {
|
||||
if (
|
||||
event.target instanceof HTMLInputElement ||
|
||||
event.target instanceof HTMLTextAreaElement ||
|
||||
(event.target as HTMLElement)?.closest('.cm-editor') ||
|
||||
(event.target as HTMLElement)?.classList?.contains('cm-content') ||
|
||||
(event.target as HTMLElement)?.classList?.contains('cm-line')
|
||||
ctx.scope !== 'global' &&
|
||||
(event.target instanceof HTMLInputElement ||
|
||||
event.target instanceof HTMLTextAreaElement ||
|
||||
(event.target as HTMLElement)?.closest('.cm-editor') ||
|
||||
(event.target as HTMLElement)?.classList?.contains('cm-content') ||
|
||||
(event.target as HTMLElement)?.classList?.contains('cm-line'))
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ export interface ModerationState {
|
||||
export type ModerationProjectContext = {
|
||||
project: Labrinth.Projects.v2.Project
|
||||
scope: 'project'
|
||||
notifyCopied: (value: string, title: string) => void
|
||||
}
|
||||
|
||||
export type ModerationChecklistContext = {
|
||||
@@ -54,10 +55,17 @@ export type ModerationTechReviewContext = {
|
||||
actions: TechReviewActions
|
||||
}
|
||||
|
||||
export type ModerationGlobalContext = {
|
||||
scope: 'global'
|
||||
officialUrl: string
|
||||
notifyCopied: (value: string, title: string) => void
|
||||
}
|
||||
|
||||
export type ModerationContext =
|
||||
| ModerationProjectContext
|
||||
| ModerationChecklistContext
|
||||
| ModerationTechReviewContext
|
||||
| ModerationGlobalContext
|
||||
|
||||
export interface KeybindDefinition {
|
||||
key: string
|
||||
@@ -71,7 +79,7 @@ export interface KeybindDefinition {
|
||||
export type BaseKeybindListener<T> = {
|
||||
keybind: KeybindDefinition | KeybindDefinition[] | string | string[]
|
||||
description: string
|
||||
scope: 'project' | 'checklist' | 'tech-review'
|
||||
scope: 'project' | 'checklist' | 'tech-review' | 'global'
|
||||
enabled?: (ctx: T) => boolean
|
||||
action: (ctx: T) => void
|
||||
}
|
||||
@@ -85,10 +93,14 @@ export type KeybindChecklistListener = BaseKeybindListener<ModerationChecklistCo
|
||||
export type KeybindTechReviewListener = BaseKeybindListener<ModerationTechReviewContext> & {
|
||||
scope: 'tech-review'
|
||||
}
|
||||
export type KeybindGlobalListener = BaseKeybindListener<ModerationGlobalContext> & {
|
||||
scope: 'global'
|
||||
}
|
||||
export type KeybindListener =
|
||||
| KeybindProjectListener
|
||||
| KeybindChecklistListener
|
||||
| KeybindTechReviewListener
|
||||
| KeybindGlobalListener
|
||||
|
||||
export function parseKeybind(keybindString: string): KeybindDefinition {
|
||||
const parts = keybindString.split('+').map((p) => p.trim().toLowerCase())
|
||||
@@ -109,12 +121,13 @@ export function normalizeKeybind(keybind: KeybindDefinition | string): KeybindDe
|
||||
|
||||
export function matchesKeybind(event: KeyboardEvent, keybind: KeybindDefinition | string): boolean {
|
||||
const def = normalizeKeybind(keybind)
|
||||
const wantsMod = !!(def.ctrl || def.meta)
|
||||
const hasMod = event.ctrlKey || event.metaKey
|
||||
return (
|
||||
event.key.toLowerCase() === def.key.toLowerCase() &&
|
||||
event.ctrlKey === (def.ctrl ?? false) &&
|
||||
hasMod === wantsMod &&
|
||||
event.shiftKey === (def.shift ?? false) &&
|
||||
event.altKey === (def.alt ?? false) &&
|
||||
event.metaKey === (def.meta ?? false)
|
||||
event.altKey === (def.alt ?? false)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user