mirror of
https://github.com/cline/cline.git
synced 2025-06-03 03:59:07 +00:00
Add sidebar code
This commit is contained in:
parent
0ede211d4f
commit
fd750864db
40
package.json
40
package.json
@ -12,12 +12,46 @@
|
||||
"activationEvents": [],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "custom-activitybar",
|
||||
"title": "VSCode Extension",
|
||||
"icon": "assets/logo_bito.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"custom-activitybar": [
|
||||
{
|
||||
"type": "webview",
|
||||
"id": "vscodeSidebar.openview",
|
||||
"name": "View",
|
||||
"contextualTitle": "View"
|
||||
}
|
||||
]
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"command": "claude-dev.helloWorld",
|
||||
"title": "Hello World"
|
||||
"command": "vscodeSidebar.openview",
|
||||
"title": "Sidebar View"
|
||||
},
|
||||
{
|
||||
"command": "vscodeSidebar.menu.view",
|
||||
"category": "vscode-extension-sidebar-html",
|
||||
"title": "Sample WebView in VS Code Sidebar",
|
||||
"icon": "$(clear-all)"
|
||||
}
|
||||
]
|
||||
],
|
||||
"menus": {
|
||||
"view/title": [
|
||||
{
|
||||
"command": "vscodeSidebar.menu.view",
|
||||
"group": "navigation",
|
||||
"when": "view == vscodeSidebar.openview"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run package",
|
||||
|
BIN
src/assets/icon.png
Normal file
BIN
src/assets/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
@ -2,6 +2,16 @@
|
||||
// Import the module and reference it with the alias vscode in your code below
|
||||
import * as vscode from "vscode"
|
||||
import { HelloWorldPanel } from "./HelloWorldPanel"
|
||||
import { SidebarProvider } from "./providers/SidebarProvider"
|
||||
|
||||
/*
|
||||
Built using https://github.com/microsoft/vscode-webview-ui-toolkit
|
||||
|
||||
Inspired by
|
||||
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/tree/main/default/weather-webview
|
||||
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/tree/main/frameworks/hello-world-react-cra
|
||||
|
||||
*/
|
||||
|
||||
// This method is called when your extension is activated
|
||||
// Your extension is activated the very first time the command is executed
|
||||
@ -21,11 +31,32 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// context.subscriptions.push(disposable)
|
||||
|
||||
const helloCommand = vscode.commands.registerCommand("claude-dev.helloWorld", () => {
|
||||
HelloWorldPanel.render(context.extensionUri)
|
||||
// const helloCommand = vscode.commands.registerCommand("claude-dev.helloWorld", () => {
|
||||
// HelloWorldPanel.render(context.extensionUri)
|
||||
// })
|
||||
|
||||
// context.subscriptions.push(helloCommand)
|
||||
|
||||
const provider = new SidebarProvider(context.extensionUri)
|
||||
|
||||
context.subscriptions.push(vscode.window.registerWebviewViewProvider(SidebarProvider.viewType, provider))
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("vscodeSidebar.menu.view", () => {
|
||||
const message = "Menu/Title of extension is clicked !"
|
||||
vscode.window.showInformationMessage(message)
|
||||
})
|
||||
)
|
||||
|
||||
// Command has been defined in the package.json file
|
||||
// Provide the implementation of the command with registerCommand
|
||||
// CommandId parameter must match the command field in package.json
|
||||
let openWebView = vscode.commands.registerCommand("vscodeSidebar.openview", () => {
|
||||
// Display a message box to the user
|
||||
vscode.window.showInformationMessage('Command " Sidebar View [vscodeSidebar.openview] " called.')
|
||||
})
|
||||
|
||||
context.subscriptions.push(helloCommand)
|
||||
context.subscriptions.push(openWebView)
|
||||
}
|
||||
|
||||
// This method is called when your extension is deactivated
|
||||
|
78
src/providers/SidebarProvider.ts
Normal file
78
src/providers/SidebarProvider.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { getUri } from "../utilities/getUri"
|
||||
import { getNonce } from "../utilities/getNonce"
|
||||
//import * as weather from "weather-js"
|
||||
import * as vscode from "vscode"
|
||||
|
||||
export class SidebarProvider implements vscode.WebviewViewProvider {
|
||||
public static readonly viewType = "vscodeSidebar.openview"
|
||||
|
||||
private _view?: vscode.WebviewView
|
||||
|
||||
constructor(private readonly _extensionUri: vscode.Uri) {}
|
||||
|
||||
resolveWebviewView(
|
||||
webviewView: vscode.WebviewView,
|
||||
context: vscode.WebviewViewResolveContext<unknown>,
|
||||
token: vscode.CancellationToken
|
||||
): void | Thenable<void> {
|
||||
this._view = webviewView
|
||||
|
||||
webviewView.webview.options = {
|
||||
// Allow scripts in the webview
|
||||
enableScripts: true,
|
||||
localResourceRoots: [this._extensionUri],
|
||||
}
|
||||
webviewView.webview.html = this.getHtmlContent(webviewView.webview)
|
||||
}
|
||||
|
||||
private getHtmlContent(webview: vscode.Webview): string {
|
||||
// Get the local path to main script run in the webview,
|
||||
// then convert it to a uri we can use in the webview.
|
||||
const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "main.js"))
|
||||
|
||||
const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "reset.css"))
|
||||
const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "vscode.css"))
|
||||
|
||||
// Same for stylesheet
|
||||
const stylesheetUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "main.css"))
|
||||
|
||||
// Use a nonce to only allow a specific script to be run.
|
||||
const nonce = getNonce()
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
|
||||
<link href="${styleResetUri}" rel="stylesheet">
|
||||
<link href="${styleVSCodeUri}" rel="stylesheet">
|
||||
|
||||
<link href="${stylesheetUri}" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section class="wrapper">
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<h2 class="subtitle">Subscribe today</h2>
|
||||
<input type="text" class="mail" placeholder="Your email address" name="mail" required>
|
||||
|
||||
<button class="add-color-button">Subscribe</button>
|
||||
|
||||
<p class="text">We won’t send you spam.</p>
|
||||
<p class="text">Unsubscribe at any time.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!--<script nonce="${nonce}" src="${scriptUri}"></script>-->
|
||||
</body>
|
||||
|
||||
</html>`
|
||||
}
|
||||
}
|
@ -1,3 +1,11 @@
|
||||
/**
|
||||
* A helper function that returns a unique alphanumeric identifier called a nonce.
|
||||
*
|
||||
* @remarks This function is primarily used to help enforce content security
|
||||
* policies for resources/scripts being executed in a webview context.
|
||||
*
|
||||
* @returns A nonce
|
||||
*/
|
||||
export function getNonce() {
|
||||
let text = ""
|
||||
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
@ -1,5 +1,16 @@
|
||||
import { Uri, Webview } from "vscode"
|
||||
|
||||
/**
|
||||
* A helper function which will get the webview URI of a given file or resource.
|
||||
*
|
||||
* @remarks This URI can be used within a webview's HTML as a link to the
|
||||
* given file/resource.
|
||||
*
|
||||
* @param webview A reference to the extension webview
|
||||
* @param extensionUri The URI of the directory containing the extension
|
||||
* @param pathList An array of strings representing the path to a file/resource
|
||||
* @returns A URI pointing to the file/resource
|
||||
*/
|
||||
export function getUri(webview: Webview, extensionUri: Uri, pathList: string[]) {
|
||||
return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList))
|
||||
}
|
||||
|
@ -1,14 +1,8 @@
|
||||
import { provideVSCodeDesignSystem, vsCodeButton, vsCodeCheckbox } from "@vscode/webview-ui-toolkit"
|
||||
// const toolkit = require("@vscode/webview-ui-toolkit")
|
||||
// /*
|
||||
// You must register the components you want to use
|
||||
// */
|
||||
|
||||
/*
|
||||
provideVSCodeDesignSystem().register(vsCodeButton(), vsCodeCheckbox())
|
||||
|
||||
const vscode = acquireVsCodeApi();
|
||||
|
||||
window.addEventListener("load", main);
|
||||
|
||||
function main() {
|
||||
// To get improved type annotations/IntelliSense the associated class for
|
||||
// a given toolkit component can be imported and used to type cast a reference
|
||||
@ -16,10 +10,165 @@ function main() {
|
||||
const howdyButton = document.getElementById("howdy") as Button;
|
||||
howdyButton?.addEventListener("click", handleHowdyClick);
|
||||
}
|
||||
|
||||
function handleHowdyClick() {
|
||||
vscode.postMessage({
|
||||
command: "hello",
|
||||
text: "Hey there partner! 🤠",
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
import {
|
||||
provideVSCodeDesignSystem,
|
||||
Button,
|
||||
Dropdown,
|
||||
ProgressRing,
|
||||
TextField,
|
||||
vsCodeButton,
|
||||
vsCodeDropdown,
|
||||
vsCodeOption,
|
||||
vsCodeTextField,
|
||||
vsCodeProgressRing,
|
||||
} from "@vscode/webview-ui-toolkit";
|
||||
|
||||
// In order to use the Webview UI Toolkit web components they
|
||||
// must be registered with the browser (i.e. webview) using the
|
||||
// syntax below.
|
||||
provideVSCodeDesignSystem().register(
|
||||
vsCodeButton(),
|
||||
vsCodeDropdown(),
|
||||
vsCodeOption(),
|
||||
vsCodeProgressRing(),
|
||||
vsCodeTextField()
|
||||
);
|
||||
|
||||
// Get access to the VS Code API from within the webview context
|
||||
const vscode = acquireVsCodeApi();
|
||||
|
||||
// Just like a regular webpage we need to wait for the webview
|
||||
// DOM to load before we can reference any of the HTML elements
|
||||
// or toolkit components
|
||||
window.addEventListener("load", main);
|
||||
|
||||
// Main function that gets executed once the webview DOM loads
|
||||
function main() {
|
||||
// To get improved type annotations/IntelliSense the associated class for
|
||||
// a given toolkit component can be imported and used to type cast a reference
|
||||
// to the element (i.e. the `as Button` syntax)
|
||||
const checkWeatherButton = document.getElementById("check-weather-button") as Button;
|
||||
checkWeatherButton.addEventListener("click", checkWeather);
|
||||
|
||||
setVSCodeMessageListener();
|
||||
}
|
||||
|
||||
function checkWeather() {
|
||||
const location = document.getElementById("location") as TextField;
|
||||
const unit = document.getElementById("unit") as Dropdown;
|
||||
|
||||
// Passes a message back to the extension context with the location that
|
||||
// should be searched for and the degree unit (F or C) that should be returned
|
||||
vscode.postMessage({
|
||||
command: "weather",
|
||||
location: location.value,
|
||||
unit: unit.value,
|
||||
});
|
||||
|
||||
displayLoadingState();
|
||||
}
|
||||
|
||||
// Sets up an event listener to listen for messages passed from the extension context
|
||||
// and executes code based on the message that is recieved
|
||||
function setVSCodeMessageListener() {
|
||||
window.addEventListener("message", (event) => {
|
||||
const command = event.data.command;
|
||||
|
||||
// switch (command) {
|
||||
// case "weather":
|
||||
// const weatherData = JSON.parse(event.data.payload);
|
||||
// displayWeatherData(weatherData);
|
||||
// break;
|
||||
// case "error":
|
||||
// displayError(event.data.message);
|
||||
// break;
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
function displayLoadingState() {
|
||||
const loading = document.getElementById("loading") as ProgressRing;
|
||||
const icon = document.getElementById("icon");
|
||||
const summary = document.getElementById("summary");
|
||||
if (loading && icon && summary) {
|
||||
loading.classList.remove("hidden");
|
||||
icon.classList.add("hidden");
|
||||
summary.textContent = "Getting weather...";
|
||||
}
|
||||
}
|
||||
|
||||
// function displayWeatherData(weatherData) {
|
||||
// const loading = document.getElementById("loading") as ProgressRing;
|
||||
// const icon = document.getElementById("icon");
|
||||
// const summary = document.getElementById("summary");
|
||||
// if (loading && icon && summary) {
|
||||
// loading.classList.add("hidden");
|
||||
// icon.classList.remove("hidden");
|
||||
// icon.textContent = getWeatherIcon(weatherData);
|
||||
// summary.textContent = getWeatherSummary(weatherData);
|
||||
// }
|
||||
// }
|
||||
|
||||
// function displayError(errorMsg) {
|
||||
// const loading = document.getElementById("loading") as ProgressRing;
|
||||
// const icon = document.getElementById("icon");
|
||||
// const summary = document.getElementById("summary");
|
||||
// if (loading && icon && summary) {
|
||||
// loading.classList.add("hidden");
|
||||
// icon.classList.add("hidden");
|
||||
// summary.textContent = errorMsg;
|
||||
// }
|
||||
// }
|
||||
|
||||
// function getWeatherSummary(weatherData) {
|
||||
// const skyText = weatherData.current.skytext;
|
||||
// const temperature = weatherData.current.temperature;
|
||||
// const degreeType = weatherData.location.degreetype;
|
||||
|
||||
// return `${skyText}, ${temperature}${degreeType}`;
|
||||
// }
|
||||
|
||||
// function getWeatherIcon(weatherData) {
|
||||
// const skyText = weatherData.current.skytext.toLowerCase();
|
||||
// let icon = "";
|
||||
|
||||
// switch (skyText) {
|
||||
// case "sunny":
|
||||
// icon = "☀️";
|
||||
// break;
|
||||
// case "mostly sunny":
|
||||
// icon = "🌤";
|
||||
// break;
|
||||
// case "partly sunny":
|
||||
// icon = "🌥";
|
||||
// break;
|
||||
// case "clear":
|
||||
// icon = "☀️";
|
||||
// break;
|
||||
// case "fair":
|
||||
// icon = "🌥";
|
||||
// break;
|
||||
// case "mostly cloudy":
|
||||
// icon = "☁️";
|
||||
// break;
|
||||
// case "cloudy":
|
||||
// icon = "☁️";
|
||||
// break;
|
||||
// case "rain showers":
|
||||
// icon = "🌦";
|
||||
// break;
|
||||
// default:
|
||||
// icon = "✨";
|
||||
// }
|
||||
|
||||
// return icon;
|
||||
// }
|
45
src/webview/styles.css
Normal file
45
src/webview/styles.css
Normal file
@ -0,0 +1,45 @@
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
#search-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#location {
|
||||
width: 100%;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
#unit {
|
||||
min-width: 30px;
|
||||
width: 100%;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
#check-weather-button {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
#results-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
background-color: var(--vscode-input-background);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#icon {
|
||||
font-size: 3em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
Loading…
Reference in New Issue
Block a user