Skip to content

Commit 6c4f798

Browse files
[feat]: add new instruction selector dropdown menu
[feat][New Feature]: Added a new instruction selector dropdown menu
2 parents cd696f8 + 5bfc494 commit 6c4f798

28 files changed

+1120
-34
lines changed

extensions/changelog.md

+13
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
# Changelog of the extensions
44

5+
## feat: Instruction Selector - 12/2/2024 - @lumpinif
6+
7+
### New Feature Implementation
8+
9+
- Added instruction selector feature for enhanced user interaction
10+
- Implemented quick instruction selection capability
11+
- Improved text insertion reliability
12+
- Restructured initialization logic for better feature scoping
13+
14+
### Version Update
15+
16+
- Bumped version to 3.2.0 to reflect new feature addition
17+
518
## feat: CSS Architecture - 12/1/2024 - @lumpinif
619

720
### Modular CSS Architecture Implementation

extensions/chrome/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "thinking-claude",
3-
"version": "3.1.5",
3+
"version": "3.2.0",
44
"description": "Chrome extension for letting Claude think like a real human",
55
"type": "module",
66
"scripts": {
@@ -21,7 +21,9 @@
2121
"dependencies": {
2222
"@radix-ui/react-accordion": "^1.2.1",
2323
"@radix-ui/react-collapsible": "^1.1.1",
24+
"@radix-ui/react-icons": "^1.3.2",
2425
"@radix-ui/react-scroll-area": "^1.2.1",
26+
"@radix-ui/react-select": "^2.1.2",
2527
"@radix-ui/react-slot": "^1.1.0",
2628
"@radix-ui/react-tooltip": "^1.1.4",
2729
"class-variance-authority": "^0.7.0",

extensions/chrome/public/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 3,
33
"name": "Thinking Claude",
4-
"version": "3.1.5",
4+
"version": "3.2.0",
55
"description": "Chrome extension for letting Claude think like a real human",
66
"background": {
77
"service_worker": "background.js"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import * as React from "react"
2+
3+
import { formatStarCount } from "@/utils/format"
4+
import { insertTextIntoClaudeInput } from "@/utils/insert-text"
5+
import { GitHubLogoIcon, StarFilledIcon } from "@radix-ui/react-icons"
6+
7+
import { cn } from "@/lib/utils"
8+
9+
import { useModelInstructions } from "@/hooks/use-model-instructions"
10+
11+
import { Badge } from "@/components/ui/badge"
12+
import {
13+
Select,
14+
SelectContent,
15+
SelectGroup,
16+
SelectTrigger,
17+
SelectValue,
18+
} from "@/components/ui/select"
19+
20+
import { useContentSync } from "../../hooks/use-content-sync"
21+
import { InstructionDescription } from "./instruction-description"
22+
import { InstructionItem } from "./instruction-item"
23+
24+
// Types
25+
export interface ModelInstruction {
26+
value: string
27+
label: string
28+
description?: string
29+
content: string
30+
}
31+
32+
const LoadingState = ({ isLoading }: { isLoading: boolean }) => (
33+
<div
34+
className={cn(
35+
"tc-min-w-24 text-text-500 tc-text-xs tc-bg-clip-text tc-text-transparent tc-bg-[length:200%_100%]",
36+
isLoading &&
37+
"tc-animate-shimmer tc-bg-gradient-to-r tc-from-gray-400/70 tc-via-gray-300 tc-to-gray-400/70"
38+
)}
39+
>
40+
Loading model instructions...
41+
</div>
42+
)
43+
44+
export function InstructionSelect() {
45+
const [value, setValue] = React.useState("")
46+
const [key, setKey] = React.useState(Date.now())
47+
const [hoveredInstruction, setHoveredInstruction] =
48+
React.useState<ModelInstruction | null>(null)
49+
const {
50+
instructions,
51+
isLoading,
52+
starsCount,
53+
handleInstructionSelect,
54+
error,
55+
} = useModelInstructions()
56+
57+
useContentSync({
58+
instructions,
59+
onValueChange: setValue,
60+
onKeyChange: () => setKey(Date.now()),
61+
})
62+
63+
const handleClear = async (e: React.MouseEvent) => {
64+
e.stopPropagation()
65+
setValue("")
66+
setKey(Date.now())
67+
await insertTextIntoClaudeInput("")
68+
}
69+
70+
const handleInstructionClick = async (instruction: ModelInstruction) => {
71+
if (instruction.content) {
72+
setValue(instruction.value)
73+
await handleInstructionSelect(instruction)
74+
}
75+
}
76+
77+
const selectedInstruction = instructions.find((inst) => inst.value === value)
78+
const displayedInstruction = hoveredInstruction || selectedInstruction
79+
80+
if (isLoading) {
81+
return <LoadingState isLoading={isLoading} />
82+
}
83+
84+
return (
85+
<div className="tc-min-w-24">
86+
<Select
87+
key={key}
88+
value={value}
89+
onValueChange={(value) => {
90+
handleInstructionClick(
91+
instructions.find((inst) => inst.value === value)!
92+
)
93+
}}
94+
>
95+
<SelectTrigger className="inline-flex items-center justify-center relative shrink-0 ring-offset-2 ring-offset-bg-300 ring-accent-main-100 focus-visible:outline-none focus-visible:ring-1 tc-shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none disabled:drop-shadow-none max-w-full min-w-0 pl-1.5 pr-1 h-7 ml-0.5 mr-1 hover:bg-bg-200 hover:border-border-400 border-0.5 text-sm rounded-md border-transparent transition text-text-500 hover:text-text-200 font-tiempos !tc-font-normal tc-gap-x-1">
96+
<SelectValue placeholder="Let Claude think" />
97+
</SelectTrigger>
98+
<SelectContent className="z-50 bg-bg-200 backdrop-blur-xl border-0.5 border-border-300 rounded-xl min-w-[12rem] overflow-hidden p-1 text-text-200 shadow-[0_0_0_0.5px_rgba(0,0,0,0.1),0_0_20px_rgba(0,0,0,0.05),0_1px_5px_rgba(0,0,0,0.1)] w-64 sm:w-[28rem] md:tc-w-[32rem] !z-30">
99+
<div className="sm:flex justify-between items-center flex-1 text-xs font-medium text-text-300 px-1.5 pt-1 pb-1.5 min-h-5">
100+
<div className="translate-y-[0.5px]">
101+
Which model instruction should Claude use?
102+
</div>
103+
<a
104+
href="https://github.com/richards199999/Thinking-Claude"
105+
target="_blank"
106+
rel="noopener noreferrer"
107+
>
108+
<Badge
109+
variant="default"
110+
className="border-0.5 border-border-300 tc-flex tc-items-center tc-gap-2 tc-cursor-pointer hover:!bg-accent-main-100 hover:!text-oncolor-100 hover:!border-transparent transition tc-font-normal tc-text-xs tc-flex-nowrap"
111+
>
112+
<span
113+
title="Open-souced on GitHub"
114+
className="tc-flex tc-items-center tc-justify-center"
115+
>
116+
<GitHubLogoIcon className="tc-size-3" />
117+
</span>
118+
<span className="tc-flex tc-items-center tc-justify-center">
119+
{starsCount && (
120+
<span
121+
className="tc-text-xs"
122+
title={`${starsCount.toLocaleString()} stars`}
123+
>
124+
{formatStarCount(starsCount)}
125+
</span>
126+
)}
127+
<StarFilledIcon className="tc-size-3" />
128+
</span>
129+
</Badge>
130+
</a>
131+
</div>
132+
<div className="grid sm:grid-cols-2 tc-gap-2 mt-0.5 pb-1 px-1">
133+
<div className="min-h-0">
134+
<div className="overflow-x-visible overflow-y-auto scroll-pb-6 min-h-[0px] [scrollbar-color:hsl(var(--text-500))] scroll-smooth overscroll-contain [-webkit-overflow-scrolling:touch] [&::-webkit-scrollbar]:mt-4 [&::-webkit-scrollbar]:w-[0.25rem] [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-track]:my-1 [&::-webkit-scrollbar-thumb]:rounded-[1em] [&::-webkit-scrollbar-thumb]:border-[0.25rem] [&::-webkit-scrollbar-thumb]:border-transparent [&::-webkit-scrollbar-thumb]:bg-clip-padding [&::-webkit-scrollbar-thumb]:bg-text-500/80 [&::-webkit-scrollbar-thumb:hover]:bg-text-500 sm:mr-1 min-h-40 max-h-64">
135+
<SelectGroup>
136+
{instructions.map((instruction) => (
137+
<div
138+
key={instruction.value}
139+
onMouseEnter={() => setHoveredInstruction(instruction)}
140+
onMouseLeave={() => setHoveredInstruction(null)}
141+
>
142+
<InstructionItem
143+
value={instruction.value}
144+
label={instruction.label}
145+
/>
146+
</div>
147+
))}
148+
<button
149+
onClick={handleClear}
150+
className="py-1 px-2 rounded-md cursor-pointer whitespace-nowrap overflow-hidden text-ellipsis grid grid-cols-[minmax(0,_1fr)_auto] gap-2 items-center outline-none select-none [&[data-highlighted]]:bg-bg-300 [&[data-highlighted]]:text-text-000 bg-transparent border-0.5 border-border-300 hover:!bg-accent-main-100 hover:!text-oncolor-100 hover:!border-transparent transition mb-1 mt-4 !rounded-lg text-center text-sm font-medium w-full"
151+
>
152+
Clear selection
153+
</button>
154+
</SelectGroup>
155+
</div>
156+
</div>
157+
<div className="flex flex-col">
158+
<InstructionDescription
159+
error={error}
160+
selectedInstruction={displayedInstruction}
161+
/>
162+
</div>
163+
</div>
164+
</SelectContent>
165+
</Select>
166+
</div>
167+
)
168+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { cn } from "@/lib/utils"
2+
3+
import type { ModelInstruction } from "."
4+
5+
interface InstructionDescriptionProps {
6+
error: string | null
7+
selectedInstruction?: ModelInstruction
8+
}
9+
10+
const convertMarkdownToHtml = (markdown: string): string => {
11+
return markdown
12+
.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>") // Bold
13+
.replace(/\*(.*?)\*/g, "<em>$1</em>") // Italic
14+
.replace(/\n/g, "<br />") // New lines
15+
}
16+
17+
export const InstructionDescription = ({
18+
error,
19+
selectedInstruction,
20+
}: InstructionDescriptionProps) => (
21+
<div className="flex-1 mr-1 mb-1 text-wrap py-3 px-3.5 gap-2.5 rounded-lg border-0.5 transition max-sm:hidden bg-bg-100/40 border-border-300 text-text-200 tc-font-light tc-text-balance">
22+
<div
23+
className={cn(
24+
"font-tiempos text-[0.9375rem] leading-snug",
25+
!error && "tc-prose tc-prose-sm tc-prose-neutral dark:tc-prose-invert",
26+
!selectedInstruction?.description &&
27+
"tc-flex tc-items-center tc-justify-center tc-size-full tc-text-center"
28+
)}
29+
>
30+
{error ? (
31+
<span className="text-danger-100">{error}</span>
32+
) : (
33+
<div
34+
key={selectedInstruction?.value} // Force re-render on instruction change
35+
className="tc-animate-fade-in"
36+
dangerouslySetInnerHTML={{
37+
__html: convertMarkdownToHtml(
38+
selectedInstruction?.description ||
39+
"Select a model instruction version to let Claude think"
40+
),
41+
}}
42+
/>
43+
)}
44+
</div>
45+
</div>
46+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { SelectItem } from "@/components/ui/select"
2+
3+
// Constants
4+
const ITEM_STYLES =
5+
"py-1 px-2 rounded-md cursor-pointer whitespace-nowrap overflow-hidden text-ellipsis grid grid-cols-[minmax(0,_1fr)_auto] gap-2 items-center outline-none select-none [&[data-highlighted]]:bg-bg-300 [&[data-highlighted]]:text-text-000 pr-0 mb-0.5 line-clamp-2 leading-tight tc-text-base tc-w-full tc-pr-6"
6+
7+
export const InstructionItem = ({
8+
value,
9+
label,
10+
}: {
11+
value: string
12+
label: string
13+
}) => (
14+
<SelectItem value={value} className={ITEM_STYLES}>
15+
<div className="flex items-center justify-between">
16+
<div
17+
className="flex-1 tc-text-nowrap tc-overflow-hidden tc-text-ellipsis"
18+
title={label}
19+
>
20+
{label}
21+
</div>
22+
</div>
23+
</SelectItem>
24+
)

extensions/chrome/src/components/sample-ui.tsx

-9
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import * as React from "react"
2+
3+
import { cva, type VariantProps } from "class-variance-authority"
4+
5+
import { cn } from "@/lib/utils"
6+
7+
const badgeVariants = cva(
8+
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
9+
{
10+
variants: {
11+
variant: {
12+
default:
13+
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
14+
secondary:
15+
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
16+
destructive:
17+
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
18+
outline: "text-foreground",
19+
},
20+
},
21+
defaultVariants: {
22+
variant: "default",
23+
},
24+
}
25+
)
26+
27+
export interface BadgeProps
28+
extends React.HTMLAttributes<HTMLDivElement>,
29+
VariantProps<typeof badgeVariants> {}
30+
31+
function Badge({ className, variant, ...props }: BadgeProps) {
32+
return (
33+
<div className={cn(badgeVariants({ variant }), className)} {...props} />
34+
)
35+
}
36+
37+
export { Badge, badgeVariants }

0 commit comments

Comments
 (0)