From b0eb943ebc86349970229fc9c5c96cb0f9caec3a Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 28 Dec 2023 01:31:09 +0700
Subject: [PATCH] getting ready for more apis...
---
.config/ags/config.js | 15 +-
.config/ags/lib/md2pango.js | 2 +-
.config/ags/scss/_sidebars.scss | 22 ++-
.config/ags/style.css | 17 +-
.config/ags/widgets/sideleft/apis/chatgpt.js | 22 ++-
.config/ags/widgets/sideleft/apis/waifu.js | 55 ++++++
.config/ags/widgets/sideleft/apiwidgets.js | 57 ++++--
.config/ags/widgets/sideleft/sideleft.js | 172 ++++++++++++-------
8 files changed, 260 insertions(+), 102 deletions(-)
create mode 100644 .config/ags/widgets/sideleft/apis/waifu.js
diff --git a/.config/ags/config.js b/.config/ags/config.js
index 3c6f9c185..4e09423df 100644
--- a/.config/ags/config.js
+++ b/.config/ags/config.js
@@ -1,7 +1,6 @@
"strict mode";
// Import
import { App, Utils } from './imports.js';
-import { firstRunWelcome } from './services/messages.js';
// Widgets
import Bar from './widgets/bar/main.js';
import Cheatsheet from './widgets/cheatsheet/main.js';
@@ -15,18 +14,20 @@ import Session from './widgets/session/main.js';
import SideLeft from './widgets/sideleft/main.js';
import SideRight from './widgets/sideright/main.js';
-// Longer than actual anim time (see styles) to make sure widgets animate fully
-const CLOSE_ANIM_TIME = 210;
+const CLOSE_ANIM_TIME = 210; // Longer than actual anim time (see styles) to make sure widgets animate fully
// Init cache and check first run
Utils.exec(`bash -c 'mkdir -p ~/.cache/ags/user/colorschemes'`);
-
// SCSS compilation
Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicwal.scss'`); // reset music styles
Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicmaterial.scss'`); // reset music styles
-Utils.exec(`sassc ${App.configDir}/scss/main.scss ${App.configDir}/style.css`);
-App.resetCss();
-App.applyCss(`${App.configDir}/style.css`);
+function applyStyle() {
+ Utils.exec(`sassc ${App.configDir}/scss/main.scss ${App.configDir}/style.css`);
+ App.resetCss();
+ App.applyCss(`${App.configDir}/style.css`);
+ console.log('[LOG] Styles loaded')
+}
+applyStyle();
// Config object
export default {
diff --git a/.config/ags/lib/md2pango.js b/.config/ags/lib/md2pango.js
index b59cd566a..e14a5cb60 100644
--- a/.config/ags/lib/md2pango.js
+++ b/.config/ags/lib/md2pango.js
@@ -28,7 +28,7 @@ const m2p_styles = [
{ name: EMPH, re: /\*(\S.*?\S)\*/g, sub: "$1" },
// { name: EMPH, re: /_(\S.*?\S)_/g, sub: "$1" },
{ name: HEXCOLOR, re: /#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g, sub: ` #$1 ` },
- { name: INLCODE, re: /(`)([^`]*)(`)/g, sub: ` $2 ` },
+ { name: INLCODE, re: /(`)([^`]*)(`)/g, sub: ` $2 ` },
// { name: UND, re: /(__|\*\*)(\S[\s\S]*?\S)(__|\*\*)/g, sub: "$2" },
]
diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss
index 61618d2f8..f2341a8ae 100644
--- a/.config/ags/scss/_sidebars.scss
+++ b/.config/ags/scss/_sidebars.scss
@@ -500,9 +500,26 @@ $onChatgpt: $onPrimary;
min-height: 1.705rem;
}
+.sidebar-chat-apiswitcher {
+ @include full-rounding;
+ @include group-padding;
+ background-color: $surface;
+}
+
+.sidebar-chat-apiswitcher-icon {
+ @include full-rounding;
+ min-width: 2.182rem;
+ min-height: 2.182rem;
+ color: $onSurface;
+}
+
+.sidebar-chat-apiswitcher-icon-enabled {
+ color: $primary;
+}
+
.sidebar-chat-viewport {
@include menu_decel;
- margin: 0.682rem 0rem;
+ // margin: 0.682rem 0rem;
padding: 0.682rem 0rem;
}
@@ -720,4 +737,5 @@ $onChatgpt: $onPrimary;
.sidebar-pin-enabled:active {
background-color: mix($primary, $onPrimary, 80%);
-}
\ No newline at end of file
+}
+
diff --git a/.config/ags/style.css b/.config/ags/style.css
index 3e3588415..53f3aec50 100644
--- a/.config/ags/style.css
+++ b/.config/ags/style.css
@@ -1769,9 +1769,24 @@ tooltip {
min-width: 1.705rem;
min-height: 1.705rem; }
+.sidebar-chat-apiswitcher {
+ border-radius: 9999px;
+ -gtk-outline-radius: 9999px;
+ padding: 0.341rem;
+ background-color: #1e1c20; }
+
+.sidebar-chat-apiswitcher-icon {
+ border-radius: 9999px;
+ -gtk-outline-radius: 9999px;
+ min-width: 2.182rem;
+ min-height: 2.182rem;
+ color: #e7e1e6; }
+
+.sidebar-chat-apiswitcher-icon-enabled {
+ color: #d6baff; }
+
.sidebar-chat-viewport {
transition: 300ms cubic-bezier(0.1, 1, 0, 1);
- margin: 0.682rem 0rem;
padding: 0.682rem 0rem; }
.sidebar-chat-textarea {
diff --git a/.config/ags/widgets/sideleft/apis/chatgpt.js b/.config/ags/widgets/sideleft/apis/chatgpt.js
index 268322c99..314877326 100644
--- a/.config/ags/widgets/sideleft/apis/chatgpt.js
+++ b/.config/ags/widgets/sideleft/apis/chatgpt.js
@@ -9,19 +9,16 @@ import { SystemMessage, ChatMessage } from "./chatgpt_chatmessage.js";
import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../../lib/configwidgets.js';
import { markdownTest } from '../../../lib/md2pango.js';
-const chatGPTTabIcon = Icon({
+export const chatGPTTabIcon = Box({
hpack: 'center',
- className: 'sidebar-chat-welcome-logo',
- icon: `${App.configDir}/assets/openai-logomark.svg`,
- setup: (self) => Utils.timeout(1, () => {
- const styleContext = self.get_style_context();
- const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
- self.size = Math.max(width, height, 1) * 116 / 180; // Why such a specific proportion? See https://openai.com/brand#logos
- })
+ className: 'sidebar-chat-apiswitcher-icon',
+ homogeneous: true,
+ children: [
+ MaterialIcon('forum', 'norm'),
+ ],
});
-export const chatGPTInfo = Box({
+const chatGPTInfo = Box({
vertical: true,
className: 'spacing-v-15',
children: [
@@ -195,11 +192,12 @@ export const chatGPTView = Scrollable({
]
}),
setup: (scrolledWindow) => {
+ // Show scrollbar
scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
const vScrollbar = scrolledWindow.get_vscrollbar();
vScrollbar.get_style_context().add_class('sidebar-scrollbar');
-
- Utils.timeout(1, () => { // Fix click-to-scroll-widget-to-view behavior
+ // Avoid click-to-scroll-widget-to-view behavior
+ Utils.timeout(1, () => {
const viewport = scrolledWindow.child;
viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
})
diff --git a/.config/ags/widgets/sideleft/apis/waifu.js b/.config/ags/widgets/sideleft/apis/waifu.js
new file mode 100644
index 000000000..34cfb0214
--- /dev/null
+++ b/.config/ags/widgets/sideleft/apis/waifu.js
@@ -0,0 +1,55 @@
+const { Gdk, GLib, Gtk, Pango } = imports.gi;
+import { App, Utils, Widget } from '../../../imports.js';
+const { Box, Button, Entry, EventBox, Icon, Label, Revealer, Scrollable, Stack } = Widget;
+const { execAsync, exec } = Utils;
+import { MaterialIcon } from "../../../lib/materialicon.js";
+import { setupCursorHover, setupCursorHoverInfo } from "../../../lib/cursorhover.js";
+
+export const waifuTabIcon = Box({
+ hpack: 'center',
+ className: 'sidebar-chat-apiswitcher-icon',
+ homogeneous: true,
+ children: [
+ MaterialIcon('photo_library', 'norm'),
+ ]
+});
+
+export const waifuView = Scrollable({
+ className: 'sidebar-chat-viewport',
+ vexpand: true,
+ child: Box({
+ vertical: true,
+ children: [
+ ]
+ }),
+ setup: (scrolledWindow) => {
+ // Show scrollbar
+ scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+ const vScrollbar = scrolledWindow.get_vscrollbar();
+ vScrollbar.get_style_context().add_class('sidebar-scrollbar');
+ // Avoid click-to-scroll-widget-to-view behavior
+ Utils.timeout(1, () => {
+ const viewport = scrolledWindow.child;
+ viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
+ })
+ }
+});
+
+export const waifuCommands = Box({
+ className: 'spacing-h-5',
+ children: [
+ Box({ hexpand: true }),
+ Button({
+ className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
+ onClicked: () => {
+ // command do something
+ },
+ setup: setupCursorHover,
+ label: '/A command button',
+ }),
+ ]
+});
+
+export const waifuCallAPI = (text) => {
+ // Do something on send
+}
\ No newline at end of file
diff --git a/.config/ags/widgets/sideleft/apiwidgets.js b/.config/ags/widgets/sideleft/apiwidgets.js
index c44ef2b39..88d1539d5 100644
--- a/.config/ags/widgets/sideleft/apiwidgets.js
+++ b/.config/ags/widgets/sideleft/apiwidgets.js
@@ -1,10 +1,12 @@
+const { Gtk, Gdk } = imports.gi;
import { App, Utils, Widget } from '../../imports.js';
const { Box, Button, Entry, EventBox, Icon, Label, Revealer, Scrollable, Stack } = Widget;
const { execAsync, exec } = Utils;
import { setupCursorHover, setupCursorHoverInfo } from "../../lib/cursorhover.js";
// APIs
import ChatGPT from '../../services/chatgpt.js';
-import { chatGPTView, chatGPTCommands, chatGPTSendMessage } from './apis/chatgpt.js';
+import { chatGPTView, chatGPTCommands, chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js';
+import { waifuView, waifuCommands, waifuCallAPI, waifuTabIcon } from './apis/waifu.js';
const APIS = [
{
@@ -12,20 +14,18 @@ const APIS = [
sendCommand: chatGPTSendMessage,
contentWidget: chatGPTView,
commandBar: chatGPTCommands,
- tabIcon: Box({}),
- }
+ tabIcon: chatGPTTabIcon,
+ },
+ {
+ name: 'Waifus',
+ sendCommand: waifuCallAPI,
+ contentWidget: waifuView,
+ commandBar: waifuCommands,
+ tabIcon: waifuTabIcon,
+ },
];
let currentApiId = 0;
-
-const apiSwitcher = Box({
- vertical: true,
- children: [
- Box({
- homogeneous: true,
- children: APIS.map(api => api.tabIcon),
- }),
- ]
-})
+APIS[currentApiId].tabIcon.toggleClassName('sidebar-chat-apiswitcher-icon-enabled', true);
export const chatEntry = Entry({
className: 'sidebar-chat-entry',
@@ -75,7 +75,36 @@ const apiCommandStack = Stack({
items: APIS.map(api => [api.name, api.commandBar]),
})
+function switchToTab(id) {
+ APIS[currentApiId].tabIcon.toggleClassName('sidebar-chat-apiswitcher-icon-enabled', false);
+ APIS[id].tabIcon.toggleClassName('sidebar-chat-apiswitcher-icon-enabled', true);
+ apiContentStack.shown = APIS[id].name;
+ apiCommandStack.shown = APIS[id].name;
+ currentApiId = id;
+}
+const apiSwitcher = Box({
+ homogeneous: true,
+ children: [
+ Box({
+ className: 'sidebar-chat-apiswitcher spacing-h-5',
+ hpack: 'center',
+ children: APIS.map((api, id) => Button({
+ child: api.tabIcon,
+ tooltipText: api.name,
+ setup: setupCursorHover,
+ onClicked: () => {
+ switchToTab(id);
+ }
+ })),
+ }),
+ ]
+})
+
export default Widget.Box({
+ properties: [
+ ['nextTab', () => switchToTab(Math.min(currentApiId + 1, APIS.length - 1))],
+ ['prevTab', () => switchToTab(Math.max(0, currentApiId-1))],
+ ],
vertical: true,
className: 'spacing-v-10',
homogeneous: false,
@@ -84,5 +113,5 @@ export default Widget.Box({
apiContentStack,
apiCommandStack,
textboxArea,
- ]
+ ],
});
diff --git a/.config/ags/widgets/sideleft/sideleft.js b/.config/ags/widgets/sideleft/sideleft.js
index 9d9954511..32150a8e3 100644
--- a/.config/ags/widgets/sideleft/sideleft.js
+++ b/.config/ags/widgets/sideleft/sideleft.js
@@ -7,105 +7,124 @@ import { setupCursorHover } from "../../lib/cursorhover.js";
import { NavigationIndicator } from "../../lib/navigationindicator.js";
import toolBox from './toolbox.js';
import apiWidgets from './apiwidgets.js';
-import { chatEntry } from './apiwidgets.js';
+import apiwidgets, { chatEntry } from './apiwidgets.js';
-const SidebarTabButton = (stack, stackItem, navIndicator, navIndex, icon, label) => Widget.Button({
+const contents = [
+ {
+ name: 'apis',
+ content: apiWidgets,
+ materialIcon: 'api',
+ friendlyName: 'APIs',
+ },
+ {
+ name: 'tools',
+ content: toolBox,
+ materialIcon: 'home_repair_service',
+ friendlyName: 'Tools',
+ },
+]
+let currentTabId = 0;
+
+const contentStack = Stack({
+ vexpand: true,
+ transition: 'slide_left_right',
+ items: contents.map(item => [item.name, item.content]),
+})
+
+function switchToTab(id) {
+ const allTabs = navTabs.get_children();
+ const tabButton = allTabs[id];
+ allTabs[currentTabId].toggleClassName('sidebar-selector-tab-active', false);
+ allTabs[id].toggleClassName('sidebar-selector-tab-active', true);
+ contentStack.shown = contents[id].name;
+ if (tabButton) {
+ // Fancy highlighter line width
+ const buttonWidth = tabButton.get_allocated_width();
+ const highlightWidth = tabButton.get_children()[0].get_allocated_width();
+ navIndicator.css = `
+ font-size: ${id}px;
+ padding: 0px ${(buttonWidth - highlightWidth) / 2}px;
+ `;
+ }
+ currentTabId = id;
+}
+const SidebarTabButton = (navIndex) => Widget.Button({
// hexpand: true,
className: 'sidebar-selector-tab',
onClicked: (self) => {
- stack.shown = stackItem;
- // Add active class to self and remove for others
- const allTabs = self.get_parent().get_children();
- for (let i = 0; i < allTabs.length; i++) {
- if (allTabs[i] != self) allTabs[i].toggleClassName('sidebar-selector-tab-active', false);
- else self.toggleClassName('sidebar-selector-tab-active', true);
- }
- // Fancy highlighter line width
- const buttonWidth = self.get_allocated_width();
- const highlightWidth = self.get_children()[0].get_allocated_width();
- navIndicator.css = `
- font-size: ${navIndex}px;
- padding: 0px ${(buttonWidth - highlightWidth) / 2}px;
- `;
+ switchToTab(navIndex);
},
child: Box({
hpack: 'center',
className: 'spacing-h-5',
children: [
- MaterialIcon(icon, 'larger'),
+ MaterialIcon(contents[navIndex].materialIcon, 'larger'),
Label({
className: 'txt txt-smallie',
- label: label,
+ label: `${contents[navIndex].friendlyName}`,
})
]
}),
setup: (button) => Utils.timeout(1, () => {
setupCursorHover(button);
- button.toggleClassName('sidebar-selector-tab-active', defaultTab === stackItem);
+ button.toggleClassName('sidebar-selector-tab-active', currentTabId == navIndex);
}),
});
-const defaultTab = 'apis';
-const contentStack = Stack({
- vexpand: true,
- transition: 'slide_left_right',
- items: [
- ['apis', apiWidgets],
- ['tools', toolBox],
- ],
-})
+const navTabs = Box({
+ homogeneous: true,
+ children: contents.map((item, id) =>
+ SidebarTabButton(id, item.materialIcon, item.friendlyName)
+ ),
+});
const navIndicator = NavigationIndicator(2, false, { // The line thing
className: 'sidebar-selector-highlight',
css: 'font-size: 0px; padding: 0rem 4.160rem;', // Shushhhh
-})
+});
const navBar = Box({
vertical: true,
hexpand: true,
children: [
- Box({
- homogeneous: true,
- children: [
- SidebarTabButton(contentStack, 'apis', navIndicator, 0, 'api', 'APIs'),
- SidebarTabButton(contentStack, 'tools', navIndicator, 1, 'home_repair_service', 'Tools'),
- ]
- }),
+ navTabs,
navIndicator,
]
-})
+});
const pinButton = Button({
properties: [
['enabled', false],
+ ['toggle', (self) => {
+ self._enabled = !self._enabled;
+ self.toggleClassName('sidebar-pin-enabled', self._enabled);
+
+ const sideleftWindow = App.getWindow('sideleft');
+ const barWindow = App.getWindow('bar');
+ const cornerTopLeftWindow = App.getWindow('cornertl');
+ const sideleftContent = sideleftWindow.get_children()[0].get_children()[0].get_children()[1];
+
+ sideleftContent.toggleClassName('sidebar-pinned', self._enabled);
+
+ if (self._enabled) {
+ sideleftWindow.layer = 'bottom';
+ barWindow.layer = 'bottom';
+ cornerTopLeftWindow.layer = 'bottom';
+ sideleftWindow.exclusivity = 'exclusive';
+ }
+ else {
+ sideleftWindow.layer = 'top';
+ barWindow.layer = 'top';
+ cornerTopLeftWindow.layer = 'top';
+ sideleftWindow.exclusivity = 'normal';
+ }
+ }],
],
vpack: 'start',
className: 'sidebar-pin',
child: MaterialIcon('push_pin', 'larger'),
tooltipText: 'Pin sidebar',
- onClicked: (self) => {
- self._enabled = !self._enabled;
- self.toggleClassName('sidebar-pin-enabled', self._enabled);
-
- const sideleftWindow = App.getWindow('sideleft');
- const barWindow = App.getWindow('bar');
- const cornerTopLeftWindow = App.getWindow('cornertl');
- const sideleftContent = sideleftWindow.get_children()[0].get_children()[0].get_children()[1];
-
- sideleftWindow.exclusivity = (self._enabled ? 'exclusive' : 'normal');
- sideleftContent.toggleClassName('sidebar-pinned', self._enabled);
-
- if(self._enabled) {
- sideleftWindow.layer = 'bottom';
- barWindow.layer = 'bottom';
- cornerTopLeftWindow.layer = 'bottom';
- }
- else {
- sideleftWindow.layer = 'top';
- barWindow.layer = 'top';
- cornerTopLeftWindow.layer = 'top';
- }
- },
+ onClicked: (self) => self._toggle(self),
// QoL: Focus Pin button on open. Hit keybind -> space/enter = toggle pin state
connections: [[App, (self, currentName, visible) => {
if (currentName === 'sideleft' && visible) {
@@ -128,7 +147,7 @@ export default () => Box({
Box({
vertical: true,
vexpand: true,
- className: 'sidebar-left',
+ className: 'sidebar-left spacing-v-10',
children: [
Box({
className: 'spacing-h-10',
@@ -147,15 +166,38 @@ export default () => Box({
}),
],
connections: [
- ['key-press-event', (widget, event) => { // Typing
- if (event.get_keyval()[1] >= 32 && event.get_keyval()[1] <= 126 &&
- widget != chatEntry && event.get_keyval()[1] != Gdk.KEY_space) {
- if (contentStack.shown == 'apis') {
+ ['key-press-event', (widget, event) => { // Handle keybinds
+ if (event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) {
+ // Pin sidebar
+ if (event.get_keyval()[1] == Gdk.KEY_p)
+ pinButton._toggle(pinButton);
+ // Switch sidebar tab
+ else if (event.get_keyval()[1] === Gdk.KEY_Page_Up)
+ switchToTab(Math.max(currentTabId - 1), 0);
+ else if (event.get_keyval()[1] === Gdk.KEY_Page_Down)
+ switchToTab(Math.min(currentTabId + 1), contents.length);
+ }
+ if (contentStack.shown == 'apis') { // If api tab is focused
+ // Automatically focus entry when typing
+ if (event.get_keyval()[1] >= 32 && event.get_keyval()[1] <= 126 &&
+ widget != chatEntry && event.get_keyval()[1] != Gdk.KEY_space) {
chatEntry.grab_focus();
chatEntry.set_text(chatEntry.text + String.fromCharCode(event.get_keyval()[1]));
chatEntry.set_position(-1);
}
+ // Switch API type
+ else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) &&
+ event.get_keyval()[1] === Gdk.KEY_Page_Down) {
+ const toSwitchTab = contentStack.get_visible_child();
+ toSwitchTab._nextTab();
+ }
+ else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) &&
+ event.get_keyval()[1] === Gdk.KEY_Page_Up) {
+ const toSwitchTab = contentStack.get_visible_child();
+ toSwitchTab._prevTab();
+ }
}
+
}],
],
});