many changed, added nixos-hardware
This commit is contained in:
parent
b0745b5bec
commit
b699fff171
149 changed files with 19124 additions and 238 deletions
78
modules/styling/config/lib/advancedwidgets.js
Normal file
78
modules/styling/config/lib/advancedwidgets.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
|
||||
const { Revealer, Scrollable } = Widget;
|
||||
|
||||
export const MarginRevealer = ({
|
||||
transition = 'slide_down',
|
||||
child,
|
||||
revealChild,
|
||||
showClass = 'element-show', // These are for animation curve, they don't really hide
|
||||
hideClass = 'element-hide', // Don't put margins in these classes!
|
||||
extraSetup = () => { },
|
||||
...rest
|
||||
}) => {
|
||||
const widget = Scrollable({
|
||||
...rest,
|
||||
attribute: {
|
||||
'revealChild': true, // It'll be set to false after init if it's supposed to hide
|
||||
'transition': transition,
|
||||
'show': () => {
|
||||
if (widget.attribute.revealChild) return;
|
||||
widget.hscroll = 'never';
|
||||
widget.vscroll = 'never';
|
||||
child.toggleClassName(hideClass, false);
|
||||
child.toggleClassName(showClass, true);
|
||||
widget.attribute.revealChild = true;
|
||||
child.css = 'margin: 0px;';
|
||||
},
|
||||
'hide': () => {
|
||||
if (!widget.attribute.revealChild) return;
|
||||
child.toggleClassName(hideClass, true);
|
||||
child.toggleClassName(showClass, false);
|
||||
widget.attribute.revealChild = false;
|
||||
if (widget.attribute.transition == 'slide_left')
|
||||
child.css = `margin-right: -${child.get_allocated_width()}px;`;
|
||||
else if (widget.attribute.transition == 'slide_right')
|
||||
child.css = `margin-left: -${child.get_allocated_width()}px;`;
|
||||
else if (widget.attribute.transition == 'slide_up')
|
||||
child.css = `margin-bottom: -${child.get_allocated_height()}px;`;
|
||||
else if (widget.attribute.transition == 'slide_down')
|
||||
child.css = `margin-top: -${child.get_allocated_height()}px;`;
|
||||
},
|
||||
'toggle': () => {
|
||||
if (widget.attribute.revealChild) widget.attribute.hide();
|
||||
else widget.attribute.show();
|
||||
},
|
||||
},
|
||||
child: child,
|
||||
hscroll: `${revealChild ? 'never' : 'always'}`,
|
||||
vscroll: `${revealChild ? 'never' : 'always'}`,
|
||||
setup: (self) => {
|
||||
extraSetup(self);
|
||||
}
|
||||
});
|
||||
child.toggleClassName(`${revealChild ? showClass : hideClass}`, true);
|
||||
return widget;
|
||||
}
|
||||
|
||||
// TODO: Allow reveal update. Currently this just helps at declaration
|
||||
export const DoubleRevealer = ({
|
||||
transition1 = 'slide_right',
|
||||
transition2 = 'slide_left',
|
||||
duration1 = 150,
|
||||
duration2 = 150,
|
||||
child,
|
||||
revealChild,
|
||||
}) => {
|
||||
return Revealer({
|
||||
transition: transition1,
|
||||
transitionDuration: duration1,
|
||||
revealChild: revealChild,
|
||||
child: Revealer({
|
||||
transition: transition2,
|
||||
transitionDuration: duration2,
|
||||
revealChild: revealChild,
|
||||
child: child,
|
||||
})
|
||||
})
|
||||
}
|
106
modules/styling/config/lib/animatedcircularprogress.js
Normal file
106
modules/styling/config/lib/animatedcircularprogress.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
const { Gtk } = imports.gi;
|
||||
const Lang = imports.lang;
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js'
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
|
||||
|
||||
// -- Styling --
|
||||
// min-height for diameter
|
||||
// min-width for trough stroke
|
||||
// padding for space between trough and progress
|
||||
// margin for space between widget and parent
|
||||
// background-color for trough color
|
||||
// color for progress color
|
||||
// -- Usage --
|
||||
// font size for progress value (0-100px) (hacky i know, but i want animations)
|
||||
export const AnimatedCircProg = ({
|
||||
initFrom = 0,
|
||||
initTo = 0,
|
||||
initAnimTime = 2900,
|
||||
initAnimPoints = 1,
|
||||
extraSetup = () => { },
|
||||
...rest
|
||||
}) => Widget.DrawingArea({
|
||||
...rest,
|
||||
css: `${initFrom != initTo ? 'font-size: ' + initFrom + 'px; transition: ' + initAnimTime + 'ms linear;' : ''}`,
|
||||
setup: (area) => {
|
||||
const styleContext = area.get_style_context();
|
||||
const width = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
const padding = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
|
||||
const marginLeft = styleContext.get_margin(Gtk.StateFlags.NORMAL).left;
|
||||
const marginRight = styleContext.get_margin(Gtk.StateFlags.NORMAL).right;
|
||||
const marginTop = styleContext.get_margin(Gtk.StateFlags.NORMAL).top;
|
||||
const marginBottom = styleContext.get_margin(Gtk.StateFlags.NORMAL).bottom;
|
||||
area.set_size_request(width + marginLeft + marginRight, height + marginTop + marginBottom);
|
||||
area.connect('draw', Lang.bind(area, (area, cr) => {
|
||||
const styleContext = area.get_style_context();
|
||||
const width = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
const padding = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
|
||||
const marginLeft = styleContext.get_margin(Gtk.StateFlags.NORMAL).left;
|
||||
const marginRight = styleContext.get_margin(Gtk.StateFlags.NORMAL).right;
|
||||
const marginTop = styleContext.get_margin(Gtk.StateFlags.NORMAL).top;
|
||||
const marginBottom = styleContext.get_margin(Gtk.StateFlags.NORMAL).bottom;
|
||||
area.set_size_request(width + marginLeft + marginRight, height + marginTop + marginBottom);
|
||||
|
||||
const progressValue = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 100.0;
|
||||
|
||||
const bg_stroke = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const fg_stroke = bg_stroke - padding;
|
||||
const radius = Math.min(width, height) / 2.0 - Math.max(bg_stroke, fg_stroke) / 2.0;
|
||||
const center_x = width / 2.0 + marginLeft;
|
||||
const center_y = height / 2.0 + marginTop;
|
||||
const start_angle = -Math.PI / 2.0;
|
||||
const end_angle = start_angle + (2 * Math.PI * progressValue);
|
||||
const start_x = center_x + Math.cos(start_angle) * radius;
|
||||
const start_y = center_y + Math.sin(start_angle) * radius;
|
||||
const end_x = center_x + Math.cos(end_angle) * radius;
|
||||
const end_y = center_y + Math.sin(end_angle) * radius;
|
||||
|
||||
// Draw background
|
||||
const background_color = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
|
||||
cr.setSourceRGBA(background_color.red, background_color.green, background_color.blue, background_color.alpha);
|
||||
cr.arc(center_x, center_y, radius, 0, 2 * Math.PI);
|
||||
cr.setLineWidth(bg_stroke);
|
||||
cr.stroke();
|
||||
|
||||
if (progressValue == 0) return;
|
||||
|
||||
// Draw progress
|
||||
const color = styleContext.get_property('color', Gtk.StateFlags.NORMAL);
|
||||
cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha);
|
||||
cr.arc(center_x, center_y, radius, start_angle, end_angle);
|
||||
cr.setLineWidth(fg_stroke);
|
||||
cr.stroke();
|
||||
|
||||
// Draw rounded ends for progress arcs
|
||||
cr.setLineWidth(0);
|
||||
cr.arc(start_x, start_y, fg_stroke / 2, 0, 0 - 0.01);
|
||||
cr.fill();
|
||||
cr.arc(end_x, end_y, fg_stroke / 2, 0, 0 - 0.01);
|
||||
cr.fill();
|
||||
}));
|
||||
|
||||
// Init animation
|
||||
if (initFrom != initTo) {
|
||||
area.css = `font-size: ${initFrom}px; transition: ${initAnimTime}ms linear;`;
|
||||
Utils.timeout(20, () => {
|
||||
area.css = `font-size: ${initTo}px;`;
|
||||
}, area)
|
||||
const transitionDistance = initTo - initFrom;
|
||||
const oneStep = initAnimTime / initAnimPoints;
|
||||
area.css = `
|
||||
font-size: ${initFrom}px;
|
||||
transition: ${oneStep}ms linear;
|
||||
`;
|
||||
for (let i = 0; i < initAnimPoints; i++) {
|
||||
Utils.timeout(Math.max(10, i * oneStep), () => {
|
||||
if(!area) return;
|
||||
area.css = `${initFrom != initTo ? 'font-size: ' + (initFrom + (transitionDistance / initAnimPoints * (i + 1))) + 'px;' : ''}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
else area.css = 'font-size: 0px;';
|
||||
extraSetup(area);
|
||||
},
|
||||
})
|
85
modules/styling/config/lib/calendarlayout.js
Normal file
85
modules/styling/config/lib/calendarlayout.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
function checkLeapYear(year) {
|
||||
return (
|
||||
year % 400 == 0 ||
|
||||
(year % 4 == 0 && year % 100 != 0));
|
||||
}
|
||||
|
||||
function getMonthDays(month, year) {
|
||||
const leapYear = checkLeapYear(year);
|
||||
if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 31;
|
||||
if (month == 2 && leapYear) return 29;
|
||||
if (month == 2 && !leapYear) return 28;
|
||||
return 30;
|
||||
}
|
||||
|
||||
function getNextMonthDays(month, year) {
|
||||
const leapYear = checkLeapYear(year);
|
||||
if (month == 1 && leapYear) return 29;
|
||||
if (month == 1 && !leapYear) return 28;
|
||||
if (month == 12) return 31;
|
||||
if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 30;
|
||||
return 31;
|
||||
}
|
||||
|
||||
function getPrevMonthDays(month, year) {
|
||||
const leapYear = checkLeapYear(year);
|
||||
if (month == 3 && leapYear) return 29;
|
||||
if (month == 3 && !leapYear) return 28;
|
||||
if (month == 1) return 31;
|
||||
if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 30;
|
||||
return 31;
|
||||
}
|
||||
|
||||
export function getCalendarLayout(dateObject, highlight) {
|
||||
if (!dateObject) dateObject = new Date();
|
||||
const weekday = (dateObject.getDay() + 6) % 7; // MONDAY IS THE FIRST DAY OF THE WEEK
|
||||
const day = dateObject.getDate();
|
||||
const month = dateObject.getMonth() + 1;
|
||||
const year = dateObject.getFullYear();
|
||||
const weekdayOfMonthFirst = (weekday + 35 - (day - 1)) % 7;
|
||||
const daysInMonth = getMonthDays(month, year);
|
||||
const daysInNextMonth = getNextMonthDays(month, year);
|
||||
const daysInPrevMonth = getPrevMonthDays(month, year);
|
||||
|
||||
// Fill
|
||||
var monthDiff = (weekdayOfMonthFirst == 0 ? 0 : -1);
|
||||
var toFill, dim;
|
||||
if(weekdayOfMonthFirst == 0) {
|
||||
toFill = 1;
|
||||
dim = daysInMonth;
|
||||
}
|
||||
else {
|
||||
toFill = (daysInPrevMonth - (weekdayOfMonthFirst - 1));
|
||||
dim = daysInPrevMonth;
|
||||
}
|
||||
var calendar = [...Array(6)].map(() => Array(7));
|
||||
var i = 0, j = 0;
|
||||
while (i < 6 && j < 7) {
|
||||
calendar[i][j] = {
|
||||
"day": toFill,
|
||||
"today": ((toFill == day && monthDiff == 0 && highlight) ? 1 : (
|
||||
monthDiff == 0 ? 0 :
|
||||
-1
|
||||
))
|
||||
};
|
||||
// Increment
|
||||
toFill++;
|
||||
if (toFill > dim) { // Next month?
|
||||
monthDiff++;
|
||||
if (monthDiff == 0)
|
||||
dim = daysInMonth;
|
||||
else if (monthDiff == 1)
|
||||
dim = daysInNextMonth;
|
||||
toFill = 1;
|
||||
}
|
||||
// Next tile
|
||||
j++;
|
||||
if (j == 7) {
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
return calendar;
|
||||
}
|
||||
|
126
modules/styling/config/lib/configwidgets.js
Normal file
126
modules/styling/config/lib/configwidgets.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
import { MaterialIcon } from './materialicon.js';
|
||||
import { setupCursorHover } from './cursorhover.js';
|
||||
const { Box, Button, Label, Revealer } = Widget;
|
||||
|
||||
export const ConfigToggle = ({ icon, name, desc = '', initValue, onChange, ...rest }) => {
|
||||
let value = initValue;
|
||||
const toggleIcon = Label({
|
||||
className: `icon-material txt-bold ${value ? '' : 'txt-poof'}`,
|
||||
label: `${value ? 'check' : ''}`,
|
||||
})
|
||||
const toggleButtonIndicator = Box({
|
||||
className: `switch-fg ${value ? 'switch-fg-true' : ''}`,
|
||||
vpack: 'center',
|
||||
hpack: 'start',
|
||||
homogeneous: true,
|
||||
children: [toggleIcon,],
|
||||
});
|
||||
const toggleButton = Box({
|
||||
hpack: 'end',
|
||||
className: `switch-bg ${value ? 'switch-bg-true' : ''}`,
|
||||
homogeneous: true,
|
||||
children: [toggleButtonIndicator,],
|
||||
});
|
||||
const widgetContent = Box({
|
||||
tooltipText: desc,
|
||||
className: 'txt spacing-h-5 configtoggle-box',
|
||||
children: [
|
||||
MaterialIcon(icon, 'norm'),
|
||||
Label({
|
||||
className: 'txt txt-small',
|
||||
label: name,
|
||||
}),
|
||||
Box({ hexpand: true }),
|
||||
toggleButton,
|
||||
]
|
||||
});
|
||||
const interactionWrapper = Button({
|
||||
attribute: {
|
||||
toggle: (newValue) => {
|
||||
value = !value;
|
||||
toggleIcon.toggleClassName('switch-fg-toggling-false', false);
|
||||
if (!value) {
|
||||
toggleIcon.label = '';
|
||||
toggleIcon.toggleClassName('txt-poof', true);
|
||||
}
|
||||
toggleButtonIndicator.toggleClassName('switch-fg-true', value);
|
||||
toggleButton.toggleClassName('switch-bg-true', value);
|
||||
if (value) Utils.timeout(1, () => {
|
||||
toggleIcon.label = 'check';
|
||||
toggleIcon.toggleClassName('txt-poof', false);
|
||||
})
|
||||
onChange(interactionWrapper, value);
|
||||
}
|
||||
},
|
||||
child: widgetContent,
|
||||
onClicked: (self) => self.attribute.toggle(self),
|
||||
setup: (button) => {
|
||||
setupCursorHover(button),
|
||||
button.connect('pressed', () => { // mouse down
|
||||
toggleIcon.toggleClassName('txt-poof', true);
|
||||
toggleIcon.toggleClassName('switch-fg-true', false);
|
||||
if (!value) toggleIcon.toggleClassName('switch-fg-toggling-false', true);
|
||||
});
|
||||
},
|
||||
...rest,
|
||||
});
|
||||
return interactionWrapper;
|
||||
}
|
||||
|
||||
export const ConfigSegmentedSelection = ({
|
||||
icon, name, desc = '',
|
||||
options = [{ name: 'Option 1', value: 0 }, { name: 'Option 2', value: 1 }],
|
||||
initIndex = 0,
|
||||
onChange,
|
||||
...rest
|
||||
}) => {
|
||||
let lastSelected = initIndex;
|
||||
let value = options[initIndex].value;
|
||||
const widget = Box({
|
||||
tooltipText: desc,
|
||||
className: 'segment-container',
|
||||
// homogeneous: true,
|
||||
children: options.map((option, id) => {
|
||||
const selectedIcon = Revealer({
|
||||
revealChild: id == initIndex,
|
||||
transition: 'slide_right',
|
||||
transitionDuration: 150,
|
||||
child: MaterialIcon('check', 'norm')
|
||||
});
|
||||
return Button({
|
||||
setup: setupCursorHover,
|
||||
className: `segment-btn ${id == initIndex ? 'segment-btn-enabled' : ''}`,
|
||||
child: Box({
|
||||
hpack: 'center',
|
||||
className: 'spacing-h-5',
|
||||
children: [
|
||||
selectedIcon,
|
||||
Label({
|
||||
label: option.name,
|
||||
})
|
||||
]
|
||||
}),
|
||||
onClicked: (self) => {
|
||||
value = option.value;
|
||||
const kids = widget.get_children();
|
||||
kids[lastSelected].toggleClassName('segment-btn-enabled', false);
|
||||
kids[lastSelected].get_children()[0].get_children()[0].revealChild = false;
|
||||
lastSelected = id;
|
||||
self.toggleClassName('segment-btn-enabled', true);
|
||||
selectedIcon.revealChild = true;
|
||||
onChange(option.value, option.name);
|
||||
}
|
||||
})
|
||||
}),
|
||||
...rest,
|
||||
});
|
||||
return widget;
|
||||
|
||||
}
|
||||
|
||||
export const ConfigGap = ({ vertical = true, size = 5, ...rest }) => Box({
|
||||
className: `gap-${vertical ? 'v' : 'h'}-${size}`,
|
||||
...rest,
|
||||
})
|
57
modules/styling/config/lib/cursorhover.js
Normal file
57
modules/styling/config/lib/cursorhover.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
const { Gdk } = imports.gi;
|
||||
|
||||
export function setupCursorHover(button) { // Hand pointing cursor on hover
|
||||
const display = Gdk.Display.get_default();
|
||||
button.connect('enter-notify-event', () => {
|
||||
const cursor = Gdk.Cursor.new_from_name(display, 'pointer');
|
||||
button.get_window().set_cursor(cursor);
|
||||
});
|
||||
|
||||
button.connect('leave-notify-event', () => {
|
||||
const cursor = Gdk.Cursor.new_from_name(display, 'default');
|
||||
button.get_window().set_cursor(cursor);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export function setupCursorHoverAim(button) { // Crosshair cursor on hover
|
||||
button.connect('enter-notify-event', () => {
|
||||
const display = Gdk.Display.get_default();
|
||||
const cursor = Gdk.Cursor.new_from_name(display, 'crosshair');
|
||||
button.get_window().set_cursor(cursor);
|
||||
});
|
||||
|
||||
button.connect('leave-notify-event', () => {
|
||||
const display = Gdk.Display.get_default();
|
||||
const cursor = Gdk.Cursor.new_from_name(display, 'default');
|
||||
button.get_window().set_cursor(cursor);
|
||||
});
|
||||
}
|
||||
|
||||
export function setupCursorHoverGrab(button) { // Hand ready to grab on hover
|
||||
button.connect('enter-notify-event', () => {
|
||||
const display = Gdk.Display.get_default();
|
||||
const cursor = Gdk.Cursor.new_from_name(display, 'grab');
|
||||
button.get_window().set_cursor(cursor);
|
||||
});
|
||||
|
||||
button.connect('leave-notify-event', () => {
|
||||
const display = Gdk.Display.get_default();
|
||||
const cursor = Gdk.Cursor.new_from_name(display, 'default');
|
||||
button.get_window().set_cursor(cursor);
|
||||
});
|
||||
}
|
||||
|
||||
export function setupCursorHoverInfo(button) { // "?" mark cursor on hover
|
||||
const display = Gdk.Display.get_default();
|
||||
button.connect('enter-notify-event', () => {
|
||||
const cursor = Gdk.Cursor.new_from_name(display, 'help');
|
||||
button.get_window().set_cursor(cursor);
|
||||
});
|
||||
|
||||
button.connect('leave-notify-event', () => {
|
||||
const cursor = Gdk.Cursor.new_from_name(display, 'default');
|
||||
button.get_window().set_cursor(cursor);
|
||||
});
|
||||
}
|
||||
|
7
modules/styling/config/lib/materialicon.js
Normal file
7
modules/styling/config/lib/materialicon.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
|
||||
export const MaterialIcon = (icon, size, props = {}) => Widget.Label({
|
||||
className: `icon-material txt-${size}`,
|
||||
label: icon,
|
||||
...props,
|
||||
})
|
86
modules/styling/config/lib/md2pango.js
Normal file
86
modules/styling/config/lib/md2pango.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Converts from Markdown to Pango. This does not support code blocks.
|
||||
// For illogical-impulse, code blocks are treated separately, in their own GtkSourceView widgets.
|
||||
// Partly inherited from https://github.com/ubunatic/md2pango
|
||||
|
||||
const monospaceFonts = 'JetBrains Mono NF, JetBrains Mono Nerd Font, JetBrains Mono NL, SpaceMono NF, SpaceMono Nerd Font, monospace';
|
||||
|
||||
const replacements = {
|
||||
'indents': [
|
||||
{ name: 'BULLET', re: /^(\s*)([\*\-]\s)(.*)(\s*)$/, sub: ' $1- $3' },
|
||||
{ name: 'NUMBERING', re: /^(\s*[0-9]+\.\s)(.*)(\s*)$/, sub: ' $1 $2' },
|
||||
],
|
||||
'escapes': [
|
||||
{ name: 'COMMENT', re: /<!--.*-->/, sub: '' },
|
||||
{ name: 'AMPERSTAND', re: /&/g, sub: '&' },
|
||||
{ name: 'LESSTHAN', re: /</g, sub: '<' },
|
||||
{ name: 'GREATERTHAN', re: />/g, sub: '>' },
|
||||
],
|
||||
'sections': [
|
||||
{ name: 'H1', re: /^(#\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="170%">$2</span>' },
|
||||
{ name: 'H2', re: /^(##\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="150%">$2</span>' },
|
||||
{ name: 'H3', re: /^(###\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="125%">$2</span>' },
|
||||
{ name: 'H4', re: /^(####\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="100%">$2</span>' },
|
||||
{ name: 'H5', re: /^(#####\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="90%">$2</span>' },
|
||||
],
|
||||
'styles': [
|
||||
{ name: 'BOLD', re: /(\*\*)(\S[\s\S]*?\S)(\*\*)/g, sub: "<b>$2</b>" },
|
||||
{ name: 'UND', re: /(__)(\S[\s\S]*?\S)(__)/g, sub: "<u>$2</u>" },
|
||||
{ name: 'EMPH', re: /\*(\S.*?\S)\*/g, sub: "<i>$1</i>" },
|
||||
// { name: 'EMPH', re: /_(\S.*?\S)_/g, sub: "<i>$1</i>" },
|
||||
{ name: 'HEXCOLOR', re: /#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g, sub: '<span bgcolor="#$1" fgcolor="#000000" font_family="' + monospaceFonts + '">#$1</span>' },
|
||||
{ name: 'INLCODE', re: /(`)([^`]*)(`)/g, sub: '<span font_weight="bold" font_family="' + monospaceFonts + '">$2</span>' },
|
||||
// { name: 'UND', re: /(__|\*\*)(\S[\s\S]*?\S)(__|\*\*)/g, sub: "<u>$2</u>" },
|
||||
],
|
||||
}
|
||||
|
||||
const replaceCategory = (text, replaces) => {
|
||||
for (const type of replaces) {
|
||||
text = text.replace(type.re, type.sub);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
// Main function
|
||||
|
||||
export default (text) => {
|
||||
let lines = text.split('\n')
|
||||
let output = [];
|
||||
// Replace
|
||||
for (const line of lines) {
|
||||
let result = line;
|
||||
result = replaceCategory(result, replacements.indents);
|
||||
result = replaceCategory(result, replacements.escapes);
|
||||
result = replaceCategory(result, replacements.sections);
|
||||
result = replaceCategory(result, replacements.styles);
|
||||
output.push(result)
|
||||
}
|
||||
// Remove trailing whitespaces
|
||||
output = output.map(line => line.replace(/ +$/, ''))
|
||||
return output.join('\n');
|
||||
}
|
||||
|
||||
export const markdownTest = `# Heading 1
|
||||
## Heading 2
|
||||
### Heading 3
|
||||
#### Heading 4
|
||||
##### Heading 5
|
||||
1. yes
|
||||
2. no
|
||||
127. well
|
||||
- Bulletpoint starting with minus
|
||||
* Bulletpoint starting with asterisk
|
||||
---
|
||||
- __Underline__ __ No underline __
|
||||
- **Bold** ** No bold **
|
||||
- _Italics1_ *Italics2* _ No Italics _
|
||||
- A color: #D6BAFF
|
||||
- nvidia green: #7ABB08
|
||||
- sub-item
|
||||
\`\`\`javascript
|
||||
// A code block!
|
||||
myArray = [23, 123, 43, 54, '6969'];
|
||||
console.log('uwu');
|
||||
\`\`\`
|
||||
- Random instruction thing
|
||||
- To update arch lincox, run \`sudo pacman -Syu\`
|
||||
`;
|
71
modules/styling/config/lib/navigationindicator.js
Normal file
71
modules/styling/config/lib/navigationindicator.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
const { Gtk } = imports.gi;
|
||||
const Lang = imports.lang;
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
|
||||
// min-height/min-width for height/width
|
||||
// background-color/color for background/indicator color
|
||||
// padding for pad of indicator
|
||||
// font-size for selected index (0-based)
|
||||
export const NavigationIndicator = (count, vertical, props) => Widget.DrawingArea({
|
||||
...props,
|
||||
setup: (area) => {
|
||||
const styleContext = area.get_style_context();
|
||||
const width = Math.max(styleContext.get_property('min-width', Gtk.StateFlags.NORMAL), area.get_allocated_width());
|
||||
const height = Math.max(styleContext.get_property('min-height', Gtk.StateFlags.NORMAL), area.get_allocated_height());
|
||||
area.set_size_request(width, height);
|
||||
|
||||
area.connect('draw', Lang.bind(area, (area, cr) => {
|
||||
const styleContext = area.get_style_context();
|
||||
const width = Math.max(styleContext.get_property('min-width', Gtk.StateFlags.NORMAL), area.get_allocated_width());
|
||||
const height = Math.max(styleContext.get_property('min-height', Gtk.StateFlags.NORMAL), area.get_allocated_height());
|
||||
// console.log('allocated width/height:', area.get_allocated_width(), '/', area.get_allocated_height())
|
||||
area.set_size_request(width, height);
|
||||
const paddingLeft = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
|
||||
const paddingRight = styleContext.get_padding(Gtk.StateFlags.NORMAL).right;
|
||||
const paddingTop = styleContext.get_padding(Gtk.StateFlags.NORMAL).top;
|
||||
const paddingBottom = styleContext.get_padding(Gtk.StateFlags.NORMAL).bottom;
|
||||
|
||||
const selectedCell = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
|
||||
|
||||
let cellWidth = width;
|
||||
let cellHeight = height;
|
||||
if (vertical) cellHeight /= count;
|
||||
else cellWidth /= count;
|
||||
const indicatorWidth = cellWidth - paddingLeft - paddingRight;
|
||||
const indicatorHeight = cellHeight - paddingTop - paddingBottom;
|
||||
|
||||
const background_color = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
|
||||
const color = styleContext.get_property('color', Gtk.StateFlags.NORMAL);
|
||||
cr.setLineWidth(2);
|
||||
// Background
|
||||
cr.setSourceRGBA(background_color.red, background_color.green, background_color.blue, background_color.alpha);
|
||||
cr.rectangle(0, 0, width, height);
|
||||
cr.fill();
|
||||
|
||||
// The indicator line
|
||||
cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha);
|
||||
if (vertical) {
|
||||
cr.rectangle(paddingLeft, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth, indicatorHeight - indicatorWidth);
|
||||
cr.stroke();
|
||||
cr.rectangle(paddingLeft, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth, indicatorHeight - indicatorWidth);
|
||||
cr.fill();
|
||||
cr.arc(paddingLeft + indicatorWidth / 2, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth / 2, Math.PI, 2 * Math.PI);
|
||||
cr.fill();
|
||||
cr.arc(paddingLeft + indicatorWidth / 2, paddingTop + cellHeight * selectedCell + indicatorHeight - indicatorWidth / 2, indicatorWidth / 2, 0, Math.PI);
|
||||
cr.fill();
|
||||
}
|
||||
else {
|
||||
cr.rectangle(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop, indicatorWidth - indicatorHeight, indicatorHeight);
|
||||
cr.stroke();
|
||||
cr.rectangle(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop, indicatorWidth - indicatorHeight, indicatorHeight);
|
||||
cr.fill();
|
||||
cr.arc(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop + indicatorHeight / 2, indicatorHeight / 2, 0.5 * Math.PI, 1.5 * Math.PI);
|
||||
cr.fill();
|
||||
cr.arc(paddingLeft + cellWidth * selectedCell + indicatorWidth - indicatorHeight / 2, paddingTop + indicatorHeight / 2, indicatorHeight / 2, -0.5 * Math.PI, 0.5 * Math.PI);
|
||||
cr.fill();
|
||||
}
|
||||
}))
|
||||
},
|
||||
})
|
||||
|
||||
|
445
modules/styling/config/lib/notification.js
Normal file
445
modules/styling/config/lib/notification.js
Normal file
|
@ -0,0 +1,445 @@
|
|||
// This file is for the actual widget for each single notification
|
||||
|
||||
const { GLib, Gdk, Gtk } = imports.gi;
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js'
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
|
||||
const { Box, EventBox, Icon, Overlay, Label, Button, Revealer } = Widget;
|
||||
import { MaterialIcon } from "./materialicon.js";
|
||||
import { setupCursorHover } from "./cursorhover.js";
|
||||
import { AnimatedCircProg } from "./animatedcircularprogress.js";
|
||||
|
||||
function guessMessageType(summary) {
|
||||
if (summary.includes('recording')) return 'screen_record';
|
||||
if (summary.includes('battery') || summary.includes('power')) return 'power';
|
||||
if (summary.includes('screenshot')) return 'screenshot_monitor';
|
||||
if (summary.includes('welcome')) return 'waving_hand';
|
||||
if (summary.includes('time')) return 'scheduleb';
|
||||
if (summary.includes('installed')) return 'download';
|
||||
if (summary.includes('update')) return 'update';
|
||||
if (summary.startsWith('file')) return 'folder_copy';
|
||||
return 'chat';
|
||||
}
|
||||
|
||||
function exists(widget) {
|
||||
return widget !== null;
|
||||
}
|
||||
|
||||
const NotificationIcon = (notifObject) => {
|
||||
// { appEntry, appIcon, image }, urgency = 'normal'
|
||||
if (notifObject.image) {
|
||||
return Box({
|
||||
valign: Gtk.Align.CENTER,
|
||||
hexpand: false,
|
||||
className: 'notif-icon',
|
||||
css: `
|
||||
background-image: url("${notifObject.image}");
|
||||
background-size: auto 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
let icon = 'NO_ICON';
|
||||
if (Utils.lookUpIcon(notifObject.appIcon))
|
||||
icon = notifObject.appIcon;
|
||||
if (Utils.lookUpIcon(notifObject.appEntry))
|
||||
icon = notifObject.appEntry;
|
||||
|
||||
return Box({
|
||||
vpack: 'center',
|
||||
hexpand: false,
|
||||
className: `notif-icon notif-icon-material-${notifObject.urgency}`,
|
||||
homogeneous: true,
|
||||
children: [
|
||||
(icon != 'NO_ICON' ?
|
||||
Icon({
|
||||
vpack: 'center',
|
||||
icon: icon,
|
||||
})
|
||||
:
|
||||
MaterialIcon(`${notifObject.urgency == 'critical' ? 'release_alert' : guessMessageType(notifObject.summary.toLowerCase())}`, 'hugerass', {
|
||||
hexpand: true,
|
||||
})
|
||||
)
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
export default ({
|
||||
notifObject,
|
||||
isPopup = false,
|
||||
props = {},
|
||||
} = {}) => {
|
||||
const popupTimeout = notifObject.timeout || (notifObject.urgency == 'critical' ? 8000 : 3000);
|
||||
const command = (isPopup ?
|
||||
() => notifObject.dismiss() :
|
||||
() => notifObject.close()
|
||||
)
|
||||
const destroyWithAnims = () => {
|
||||
widget.sensitive = false;
|
||||
notificationBox.setCss(middleClickClose);
|
||||
Utils.timeout(200, () => {
|
||||
if (wholeThing) wholeThing.revealChild = false;
|
||||
}, wholeThing);
|
||||
Utils.timeout(400, () => {
|
||||
command();
|
||||
if (wholeThing) {
|
||||
wholeThing.destroy();
|
||||
wholeThing = null;
|
||||
}
|
||||
}, wholeThing);
|
||||
}
|
||||
const widget = EventBox({
|
||||
onHover: (self) => {
|
||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
||||
if (!wholeThing.attribute.hovered)
|
||||
wholeThing.attribute.hovered = true;
|
||||
},
|
||||
onHoverLost: (self) => {
|
||||
self.window.set_cursor(null);
|
||||
if (wholeThing.attribute.hovered)
|
||||
wholeThing.attribute.hovered = false;
|
||||
if (isPopup) {
|
||||
command();
|
||||
}
|
||||
},
|
||||
onMiddleClick: (self) => {
|
||||
destroyWithAnims();
|
||||
},
|
||||
setup: (self) => {
|
||||
self.on("button-press-event", () => {
|
||||
wholeThing.attribute.held = true;
|
||||
notificationContent.toggleClassName(`${isPopup ? 'popup-' : ''}notif-clicked-${notifObject.urgency}`, true);
|
||||
Utils.timeout(800, () => {
|
||||
if (wholeThing?.attribute.held) {
|
||||
Utils.execAsync(['wl-copy', `${notifObject.body}`])
|
||||
notifTextSummary.label = notifObject.summary + " (copied)";
|
||||
Utils.timeout(3000, () => notifTextSummary.label = notifObject.summary)
|
||||
}
|
||||
})
|
||||
}).on("button-release-event", () => {
|
||||
wholeThing.attribute.held = false;
|
||||
notificationContent.toggleClassName(`${isPopup ? 'popup-' : ''}notif-clicked-${notifObject.urgency}`, false);
|
||||
})
|
||||
}
|
||||
});
|
||||
let wholeThing = Revealer({
|
||||
attribute: {
|
||||
'close': undefined,
|
||||
'destroyWithAnims': destroyWithAnims,
|
||||
'dragging': false,
|
||||
'held': false,
|
||||
'hovered': false,
|
||||
'id': notifObject.id,
|
||||
},
|
||||
revealChild: false,
|
||||
transition: 'slide_down',
|
||||
transitionDuration: 200,
|
||||
child: Box({ // Box to make sure css-based spacing works
|
||||
homogeneous: true,
|
||||
}),
|
||||
});
|
||||
|
||||
const display = Gdk.Display.get_default();
|
||||
const notifTextPreview = Revealer({
|
||||
transition: 'slide_down',
|
||||
transitionDuration: 120,
|
||||
revealChild: true,
|
||||
child: Label({
|
||||
xalign: 0,
|
||||
className: `txt-smallie notif-body-${notifObject.urgency}`,
|
||||
useMarkup: true,
|
||||
xalign: 0,
|
||||
justify: Gtk.Justification.LEFT,
|
||||
maxWidthChars: 24,
|
||||
truncate: 'end',
|
||||
label: notifObject.body.split("\n")[0],
|
||||
}),
|
||||
});
|
||||
const notifTextExpanded = Revealer({
|
||||
transition: 'slide_up',
|
||||
transitionDuration: 120,
|
||||
revealChild: false,
|
||||
child: Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-10',
|
||||
children: [
|
||||
Label({
|
||||
xalign: 0,
|
||||
className: `txt-smallie notif-body-${notifObject.urgency}`,
|
||||
useMarkup: true,
|
||||
xalign: 0,
|
||||
justify: Gtk.Justification.LEFT,
|
||||
maxWidthChars: 24,
|
||||
wrap: true,
|
||||
label: notifObject.body,
|
||||
}),
|
||||
Box({
|
||||
className: 'notif-actions spacing-h-5',
|
||||
children: [
|
||||
Button({
|
||||
hexpand: true,
|
||||
className: `notif-action notif-action-${notifObject.urgency}`,
|
||||
onClicked: () => destroyWithAnims(),
|
||||
child: Label({
|
||||
label: 'Close',
|
||||
})
|
||||
}),
|
||||
...notifObject.actions.map(action => Widget.Button({
|
||||
hexpand: true,
|
||||
className: `notif-action notif-action-${notifObject.urgency}`,
|
||||
onClicked: () => notifObject.invoke(action.id),
|
||||
child: Label({
|
||||
label: action.label,
|
||||
})
|
||||
}))
|
||||
],
|
||||
})
|
||||
]
|
||||
}),
|
||||
});
|
||||
const notifIcon = Box({
|
||||
vpack: 'start',
|
||||
homogeneous: true,
|
||||
children: [
|
||||
Overlay({
|
||||
child: NotificationIcon(notifObject),
|
||||
overlays: isPopup ? [AnimatedCircProg({
|
||||
className: `notif-circprog-${notifObject.urgency}`,
|
||||
vpack: 'center', hpack: 'center',
|
||||
initFrom: (isPopup ? 100 : 0),
|
||||
initTo: 0,
|
||||
initAnimTime: popupTimeout,
|
||||
})] : [],
|
||||
}),
|
||||
]
|
||||
});
|
||||
let notifTime = '';
|
||||
const messageTime = GLib.DateTime.new_from_unix_local(notifObject.time);
|
||||
if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year())
|
||||
notifTime = messageTime.format('%H:%M');
|
||||
else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year() - 1)
|
||||
notifTime = 'Yesterday';
|
||||
else
|
||||
notifTime = messageTime.format('%d/%m');
|
||||
const notifTextSummary = Label({
|
||||
xalign: 0,
|
||||
className: 'txt-small txt-semibold titlefont',
|
||||
justify: Gtk.Justification.LEFT,
|
||||
hexpand: true,
|
||||
maxWidthChars: 24,
|
||||
truncate: 'end',
|
||||
ellipsize: 3,
|
||||
useMarkup: notifObject.summary.startsWith('<'),
|
||||
label: notifObject.summary,
|
||||
});
|
||||
const notifTextBody = Label({
|
||||
vpack: 'center',
|
||||
justification: 'right',
|
||||
className: 'txt-smaller txt-semibold',
|
||||
label: notifTime,
|
||||
});
|
||||
const notifText = Box({
|
||||
valign: Gtk.Align.CENTER,
|
||||
vertical: true,
|
||||
hexpand: true,
|
||||
children: [
|
||||
Box({
|
||||
children: [
|
||||
notifTextSummary,
|
||||
notifTextBody,
|
||||
]
|
||||
}),
|
||||
notifTextPreview,
|
||||
notifTextExpanded,
|
||||
]
|
||||
});
|
||||
const notifExpandButton = Button({
|
||||
vpack: 'start',
|
||||
className: 'notif-expand-btn',
|
||||
onClicked: (self) => {
|
||||
if (notifTextPreview.revealChild) { // Expanding...
|
||||
notifTextPreview.revealChild = false;
|
||||
notifTextExpanded.revealChild = true;
|
||||
self.child.label = 'expand_less';
|
||||
expanded = true;
|
||||
}
|
||||
else {
|
||||
notifTextPreview.revealChild = true;
|
||||
notifTextExpanded.revealChild = false;
|
||||
self.child.label = 'expand_more';
|
||||
expanded = false;
|
||||
}
|
||||
},
|
||||
child: MaterialIcon('expand_more', 'norm', {
|
||||
vpack: 'center',
|
||||
}),
|
||||
setup: setupCursorHover,
|
||||
});
|
||||
const notificationContent = Box({
|
||||
...props,
|
||||
className: `${isPopup ? 'popup-' : ''}notif-${notifObject.urgency} spacing-h-10`,
|
||||
children: [
|
||||
notifIcon,
|
||||
Box({
|
||||
className: 'spacing-h-5',
|
||||
children: [
|
||||
notifText,
|
||||
notifExpandButton,
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
|
||||
// Gesture stuff
|
||||
const gesture = Gtk.GestureDrag.new(widget);
|
||||
var initDirX = 0;
|
||||
var initDirVertical = -1; // -1: unset, 0: horizontal, 1: vertical
|
||||
var expanded = false;
|
||||
// in px
|
||||
const startMargin = 0;
|
||||
const MOVE_THRESHOLD = 10;
|
||||
const DRAG_CONFIRM_THRESHOLD = 100;
|
||||
// in rem
|
||||
const maxOffset = 10.227;
|
||||
const endMargin = 20.455;
|
||||
const disappearHeight = 6.818;
|
||||
const leftAnim1 = `transition: 200ms cubic-bezier(0.05, 0.7, 0.1, 1);
|
||||
margin-left: -${Number(maxOffset + endMargin)}rem;
|
||||
margin-right: ${Number(maxOffset + endMargin)}rem;
|
||||
opacity: 0;`;
|
||||
|
||||
const rightAnim1 = `transition: 200ms cubic-bezier(0.05, 0.7, 0.1, 1);
|
||||
margin-left: ${Number(maxOffset + endMargin)}rem;
|
||||
margin-right: -${Number(maxOffset + endMargin)}rem;
|
||||
opacity: 0;`;
|
||||
|
||||
const middleClickClose = `transition: 200ms cubic-bezier(0.85, 0, 0.15, 1);
|
||||
margin-left: ${Number(maxOffset + endMargin)}rem;
|
||||
margin-right: -${Number(maxOffset + endMargin)}rem;
|
||||
opacity: 0;`;
|
||||
|
||||
const notificationBox = Box({
|
||||
attribute: {
|
||||
'leftAnim1': leftAnim1,
|
||||
'rightAnim1': rightAnim1,
|
||||
'middleClickClose': middleClickClose,
|
||||
'ready': false,
|
||||
},
|
||||
homogeneous: true,
|
||||
children: [notificationContent],
|
||||
setup: (self) => self
|
||||
.hook(gesture, self => {
|
||||
var offset_x = gesture.get_offset()[1];
|
||||
var offset_y = gesture.get_offset()[2];
|
||||
// Which dir?
|
||||
if (initDirVertical == -1) {
|
||||
if (Math.abs(offset_y) > MOVE_THRESHOLD)
|
||||
initDirVertical = 1;
|
||||
if (initDirX == 0 && Math.abs(offset_x) > MOVE_THRESHOLD) {
|
||||
initDirVertical = 0;
|
||||
initDirX = (offset_x > 0 ? 1 : -1);
|
||||
}
|
||||
}
|
||||
// Horizontal drag
|
||||
if (initDirVertical == 0 && offset_x > MOVE_THRESHOLD) {
|
||||
if (initDirX < 0)
|
||||
self.setCss(`margin-left: 0px; margin-right: 0px;`);
|
||||
else
|
||||
self.setCss(`
|
||||
margin-left: ${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
|
||||
margin-right: -${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
|
||||
`);
|
||||
}
|
||||
else if (initDirVertical == 0 && offset_x < -MOVE_THRESHOLD) {
|
||||
if (initDirX > 0)
|
||||
self.setCss(`margin-left: 0px; margin-right: 0px;`);
|
||||
else {
|
||||
offset_x = Math.abs(offset_x);
|
||||
self.setCss(`
|
||||
margin-right: ${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
|
||||
margin-left: -${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
|
||||
`);
|
||||
}
|
||||
}
|
||||
// Update dragging
|
||||
wholeThing.attribute.dragging = Math.abs(offset_x) > MOVE_THRESHOLD;
|
||||
if (Math.abs(offset_x) > MOVE_THRESHOLD ||
|
||||
Math.abs(offset_y) > MOVE_THRESHOLD) wholeThing.attribute.held = false;
|
||||
widget.window?.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
|
||||
// Vertical drag
|
||||
if (initDirVertical == 1 && offset_y > MOVE_THRESHOLD && !expanded) {
|
||||
notifTextPreview.revealChild = false;
|
||||
notifTextExpanded.revealChild = true;
|
||||
expanded = true;
|
||||
notifExpandButton.child.label = 'expand_less';
|
||||
}
|
||||
else if (initDirVertical == 1 && offset_y < -MOVE_THRESHOLD && expanded) {
|
||||
notifTextPreview.revealChild = true;
|
||||
notifTextExpanded.revealChild = false;
|
||||
expanded = false;
|
||||
notifExpandButton.child.label = 'expand_more';
|
||||
}
|
||||
|
||||
}, 'drag-update')
|
||||
.hook(gesture, self => {
|
||||
if (!self.attribute.ready) {
|
||||
wholeThing.revealChild = true;
|
||||
self.attribute.ready = true;
|
||||
return;
|
||||
}
|
||||
const offset_h = gesture.get_offset()[1];
|
||||
|
||||
if (Math.abs(offset_h) > DRAG_CONFIRM_THRESHOLD && offset_h * initDirX > 0) {
|
||||
if (offset_h > 0) {
|
||||
self.setCss(rightAnim1);
|
||||
widget.sensitive = false;
|
||||
}
|
||||
else {
|
||||
self.setCss(leftAnim1);
|
||||
widget.sensitive = false;
|
||||
}
|
||||
Utils.timeout(200, () => {
|
||||
if (wholeThing) wholeThing.revealChild = false;
|
||||
}, wholeThing);
|
||||
Utils.timeout(400, () => {
|
||||
command();
|
||||
if (wholeThing) {
|
||||
wholeThing.destroy();
|
||||
wholeThing = null;
|
||||
}
|
||||
}, wholeThing);
|
||||
}
|
||||
else {
|
||||
self.setCss(`transition: margin 200ms cubic-bezier(0.05, 0.7, 0.1, 1), opacity 200ms cubic-bezier(0.05, 0.7, 0.1, 1);
|
||||
margin-left: ${startMargin}px;
|
||||
margin-right: ${startMargin}px;
|
||||
margin-bottom: unset; margin-top: unset;
|
||||
opacity: 1;`);
|
||||
if (widget.window)
|
||||
widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
||||
|
||||
wholeThing.attribute.dragging = false;
|
||||
}
|
||||
initDirX = 0;
|
||||
initDirVertical = -1;
|
||||
}, 'drag-end')
|
||||
,
|
||||
})
|
||||
widget.add(notificationBox);
|
||||
wholeThing.child.children = [widget];
|
||||
if (isPopup) Utils.timeout(popupTimeout, () => {
|
||||
if (wholeThing) {
|
||||
wholeThing.revealChild = false;
|
||||
Utils.timeout(200, () => {
|
||||
if (wholeThing) {
|
||||
wholeThing.destroy();
|
||||
wholeThing = null;
|
||||
}
|
||||
command();
|
||||
}, wholeThing);
|
||||
}
|
||||
})
|
||||
return wholeThing;
|
||||
}
|
30
modules/styling/config/lib/popupwindow.js
Normal file
30
modules/styling/config/lib/popupwindow.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
const { Box, Window } = Widget;
|
||||
|
||||
|
||||
export default ({
|
||||
name,
|
||||
child,
|
||||
showClassName,
|
||||
hideClassName,
|
||||
...props
|
||||
}) => Window({
|
||||
name,
|
||||
popup: true,
|
||||
visible: false,
|
||||
layer: 'overlay',
|
||||
...props,
|
||||
|
||||
child: Box({
|
||||
className: `${showClassName} ${hideClassName}`,
|
||||
setup: (self) => self
|
||||
.hook(App, (self, currentName, visible) => {
|
||||
if (currentName === name) {
|
||||
self.toggleClassName(hideClassName, !visible);
|
||||
}
|
||||
})
|
||||
,
|
||||
child: child,
|
||||
}),
|
||||
});
|
54
modules/styling/config/lib/roundedcorner.js
Normal file
54
modules/styling/config/lib/roundedcorner.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
const { Gtk } = imports.gi;
|
||||
const Lang = imports.lang;
|
||||
import Cairo from 'gi://cairo?version=1.0';
|
||||
|
||||
export const dummyRegion = new Cairo.Region();
|
||||
export const enableClickthrough = (self) => self.input_shape_combine_region(dummyRegion);
|
||||
|
||||
export const RoundedCorner = (place, props) => Widget.DrawingArea({
|
||||
...props,
|
||||
hpack: place.includes('left') ? 'start' : 'end',
|
||||
vpack: place.includes('top') ? 'start' : 'end',
|
||||
setup: (widget) => Utils.timeout(1, () => {
|
||||
const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL);
|
||||
const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
|
||||
widget.set_size_request(r, r);
|
||||
widget.connect('draw', Lang.bind(widget, (widget, cr) => {
|
||||
const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL);
|
||||
const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
|
||||
// const borderColor = widget.get_style_context().get_property('color', Gtk.StateFlags.NORMAL);
|
||||
// const borderWidth = widget.get_style_context().get_border(Gtk.StateFlags.NORMAL).left; // ur going to write border-width: something anyway
|
||||
widget.set_size_request(r, r);
|
||||
|
||||
switch (place) {
|
||||
case 'topleft':
|
||||
cr.arc(r, r, r, Math.PI, 3 * Math.PI / 2);
|
||||
cr.lineTo(0, 0);
|
||||
break;
|
||||
|
||||
case 'topright':
|
||||
cr.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI);
|
||||
cr.lineTo(r, 0);
|
||||
break;
|
||||
|
||||
case 'bottomleft':
|
||||
cr.arc(r, 0, r, Math.PI / 2, Math.PI);
|
||||
cr.lineTo(0, r);
|
||||
break;
|
||||
|
||||
case 'bottomright':
|
||||
cr.arc(0, 0, r, 0, Math.PI / 2);
|
||||
cr.lineTo(r, r);
|
||||
break;
|
||||
}
|
||||
|
||||
cr.closePath();
|
||||
cr.setSourceRGBA(c.red, c.green, c.blue, c.alpha);
|
||||
cr.fill();
|
||||
// cr.setLineWidth(borderWidth);
|
||||
// cr.setSourceRGBA(borderColor.red, borderColor.green, borderColor.blue, borderColor.alpha);
|
||||
// cr.stroke();
|
||||
}));
|
||||
}),
|
||||
});
|
5
modules/styling/config/lib/separator.js
Normal file
5
modules/styling/config/lib/separator.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
|
||||
export const separatorLine = Widget.Box({
|
||||
className: 'separator-line',
|
||||
})
|
253
modules/styling/config/lib/statusicons.js
Normal file
253
modules/styling/config/lib/statusicons.js
Normal file
|
@ -0,0 +1,253 @@
|
|||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
import { MaterialIcon } from './materialicon.js';
|
||||
import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
|
||||
import Network from 'resource:///com/github/Aylur/ags/service/network.js';
|
||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||
import { languages } from '../data/languages.js';
|
||||
|
||||
// A guessing func to try to support langs not listed in data/languages.js
|
||||
function isLanguageMatch(abbreviation, word) {
|
||||
const lowerAbbreviation = abbreviation.toLowerCase();
|
||||
const lowerWord = word.toLowerCase();
|
||||
let j = 0;
|
||||
for (let i = 0; i < lowerWord.length; i++) {
|
||||
if (lowerWord[i] === lowerAbbreviation[j]) {
|
||||
j++;
|
||||
}
|
||||
if (j === lowerAbbreviation.length) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export const NotificationIndicator = (notifCenterName = 'sideright') => {
|
||||
const widget = Widget.Revealer({
|
||||
transition: 150,
|
||||
transition: 'slide_left',
|
||||
revealChild: false,
|
||||
setup: (self) => self
|
||||
.hook(Notifications, (self, id) => {
|
||||
if (!id || Notifications.dnd) return;
|
||||
if (!Notifications.getNotification(id)) return;
|
||||
self.revealChild = true;
|
||||
}, 'notified')
|
||||
.hook(App, (self, currentName, visible) => {
|
||||
if (visible && currentName === notifCenterName) {
|
||||
self.revealChild = false;
|
||||
}
|
||||
})
|
||||
,
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
MaterialIcon('notifications', 'norm'),
|
||||
Widget.Label({
|
||||
className: 'txt-small titlefont',
|
||||
attribute: {
|
||||
unreadCount: 0,
|
||||
update: (self) => self.label = `${self.attribute.unreadCount}`,
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(Notifications, (self, id) => {
|
||||
if (!id || Notifications.dnd) return;
|
||||
if (!Notifications.getNotification(id)) return;
|
||||
self.attribute.unreadCount++;
|
||||
self.attribute.update(self);
|
||||
}, 'notified')
|
||||
.hook(App, (self, currentName, visible) => {
|
||||
if (visible && currentName === notifCenterName) {
|
||||
self.attribute.unreadCount = 0;
|
||||
self.attribute.update(self);
|
||||
}
|
||||
})
|
||||
,
|
||||
})
|
||||
]
|
||||
})
|
||||
});
|
||||
return widget;
|
||||
}
|
||||
|
||||
export const BluetoothIndicator = () => Widget.Stack({
|
||||
transition: 'slide_up_down',
|
||||
children: {
|
||||
'false': Widget.Label({ className: 'txt-norm icon-material', label: 'bluetooth_disabled' }),
|
||||
'true': Widget.Label({ className: 'txt-norm icon-material', label: 'bluetooth' }),
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(Bluetooth, stack => {
|
||||
stack.shown = String(Bluetooth.enabled);
|
||||
})
|
||||
,
|
||||
});
|
||||
|
||||
|
||||
const NetworkWiredIndicator = () => Widget.Stack({
|
||||
transition: 'slide_up_down',
|
||||
children: {
|
||||
'fallback': SimpleNetworkIndicator(),
|
||||
'unknown': Widget.Label({ className: 'txt-norm icon-material', label: 'wifi_off' }),
|
||||
'disconnected': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_off' }),
|
||||
'connected': Widget.Label({ className: 'txt-norm icon-material', label: 'lan' }),
|
||||
'connecting': Widget.Label({ className: 'txt-norm icon-material', label: 'settings_ethernet' }),
|
||||
},
|
||||
setup: (self) => self.hook(Network, stack => {
|
||||
if (!Network.wired)
|
||||
return;
|
||||
|
||||
const { internet } = Network.wired;
|
||||
if (['connecting', 'connected'].includes(internet))
|
||||
stack.shown = internet;
|
||||
else if (Network.connectivity !== 'full')
|
||||
stack.shown = 'disconnected';
|
||||
else
|
||||
stack.shown = 'fallback';
|
||||
}),
|
||||
});
|
||||
|
||||
const SimpleNetworkIndicator = () => Widget.Icon({
|
||||
setup: (self) => self.hook(Network, self => {
|
||||
const icon = Network[Network.primary || 'wifi']?.iconName;
|
||||
self.icon = icon || '';
|
||||
self.visible = icon;
|
||||
}),
|
||||
});
|
||||
|
||||
const NetworkWifiIndicator = () => Widget.Stack({
|
||||
transition: 'slide_up_down',
|
||||
children: {
|
||||
'disabled': Widget.Label({ className: 'txt-norm icon-material', label: 'wifi_off' }),
|
||||
'disconnected': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_off' }),
|
||||
'connecting': Widget.Label({ className: 'txt-norm icon-material', label: 'settings_ethernet' }),
|
||||
'0': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_0_bar' }),
|
||||
'1': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_1_bar' }),
|
||||
'2': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_2_bar' }),
|
||||
'3': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_3_bar' }),
|
||||
'4': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_4_bar' }),
|
||||
},
|
||||
setup: (self) => self.hook(Network, (stack) => {
|
||||
if (!Network.wifi) {
|
||||
return;
|
||||
}
|
||||
if (Network.wifi.internet == 'connected') {
|
||||
stack.shown = String(Math.ceil(Network.wifi.strength / 25));
|
||||
}
|
||||
else if (["disconnected", "connecting"].includes(Network.wifi.internet)) {
|
||||
stack.shown = Network.wifi.internet;
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
export const NetworkIndicator = () => Widget.Stack({
|
||||
transition: 'slide_up_down',
|
||||
children: {
|
||||
'fallback': SimpleNetworkIndicator(),
|
||||
'wifi': NetworkWifiIndicator(),
|
||||
'wired': NetworkWiredIndicator(),
|
||||
},
|
||||
setup: (self) => self.hook(Network, stack => {
|
||||
if (!Network.primary) {
|
||||
stack.shown = 'wifi';
|
||||
return;
|
||||
}
|
||||
const primary = Network.primary || 'fallback';
|
||||
if (['wifi', 'wired'].includes(primary))
|
||||
stack.shown = primary;
|
||||
else
|
||||
stack.shown = 'fallback';
|
||||
}),
|
||||
});
|
||||
|
||||
const HyprlandXkbKeyboardLayout = async ({ useFlag } = {}) => {
|
||||
try {
|
||||
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
|
||||
var initLangs = [];
|
||||
var languageStackArray = [];
|
||||
var currentKeyboard;
|
||||
|
||||
const updateCurrentKeyboards = () => {
|
||||
currentKeyboard = JSON.parse(Utils.exec('hyprctl -j devices')).keyboards
|
||||
.find(device => device.name === 'at-translated-set-2-keyboard');
|
||||
if (currentKeyboard) {
|
||||
initLangs = currentKeyboard.layout.split(',').map(lang => lang.trim());
|
||||
}
|
||||
languageStackArray = Array.from({ length: initLangs.length }, (_, i) => {
|
||||
const lang = languages.find(lang => lang.layout == initLangs[i]);
|
||||
// if (!lang) return [
|
||||
// initLangs[i],
|
||||
// Widget.Label({ label: initLangs[i] })
|
||||
// ];
|
||||
// return [
|
||||
// lang.layout,
|
||||
// Widget.Label({ label: (useFlag ? lang.flag : lang.layout) })
|
||||
// ];
|
||||
// Object
|
||||
if (!lang) return {
|
||||
[initLangs[i]]: Widget.Label({ label: initLangs[i] })
|
||||
};
|
||||
return {
|
||||
[lang.layout]: Widget.Label({ label: (useFlag ? lang.flag : lang.layout) })
|
||||
};
|
||||
});
|
||||
};
|
||||
updateCurrentKeyboards();
|
||||
const widgetRevealer = Widget.Revealer({
|
||||
transition: 150,
|
||||
transition: 'slide_left',
|
||||
revealChild: languageStackArray.length > 1,
|
||||
});
|
||||
const widgetKids = {
|
||||
...languageStackArray.reduce((obj, lang) => {
|
||||
return { ...obj, ...lang };
|
||||
}, {}),
|
||||
'undef': Widget.Label({ label: '?' }),
|
||||
}
|
||||
const widgetContent = Widget.Stack({
|
||||
transition: 'slide_up_down',
|
||||
children: widgetKids,
|
||||
setup: (self) => self.hook(Hyprland, (stack, kbName, layoutName) => {
|
||||
if (!kbName) {
|
||||
return;
|
||||
}
|
||||
var lang = languages.find(lang => layoutName.includes(lang.name));
|
||||
if (lang) {
|
||||
widgetContent.shown = lang.layout;
|
||||
}
|
||||
else { // Attempt to support langs not listed
|
||||
lang = languageStackArray.find(lang => isLanguageMatch(lang[0], layoutName));
|
||||
if (!lang) stack.shown = 'undef';
|
||||
else stack.shown = lang[0];
|
||||
}
|
||||
}, 'keyboard-layout'),
|
||||
});
|
||||
widgetRevealer.child = widgetContent;
|
||||
return widgetRevealer;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const OptionalKeyboardLayout = async () => {
|
||||
try {
|
||||
return await HyprlandXkbKeyboardLayout({ useFlag: false });
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
const optionalKeyboardLayoutInstance = await OptionalKeyboardLayout();
|
||||
|
||||
export const StatusIcons = (props = {}) => Widget.Box({
|
||||
...props,
|
||||
child: Widget.Box({
|
||||
className: 'spacing-h-15',
|
||||
children: [
|
||||
optionalKeyboardLayoutInstance,
|
||||
NotificationIndicator(),
|
||||
NetworkIndicator(),
|
||||
BluetoothIndicator(),
|
||||
]
|
||||
})
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue