Merge branch 'dev' of github.com:noctalia-dev/noctalia-shell into dev
This commit is contained in:
commit
ba69ccbf82
5 changed files with 72 additions and 179 deletions
33
.github/workflows/release.yml
vendored
33
.github/workflows/release.yml
vendored
|
|
@ -27,30 +27,19 @@ jobs:
|
|||
mv *.tar.gz ${{ github.workspace }}/
|
||||
|
||||
- name: Generate release notes
|
||||
id: release_notes
|
||||
run: |
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 @^ 2>/dev/null || echo "")
|
||||
RANGE="${PREV_TAG}..HEAD"
|
||||
|
||||
PR_NOTES=""
|
||||
COMMIT_NOTES=""
|
||||
|
||||
git log $RANGE --pretty=format:"%H|%s|%an" | while IFS='|' read -r SHA MSG AUTHOR; do
|
||||
SHORT_MSG=$(echo "$MSG" | cut -c1-80)
|
||||
if [[ "$MSG" =~ Merge\ pull\ request\ \#([0-9]+) ]]; then
|
||||
PR_NUM="${BASH_REMATCH[1]}"
|
||||
PR_TITLE=$(echo "$SHORT_MSG" | sed -E "s/Merge pull request #$PR_NUM //")
|
||||
PR_NOTES+="- [PR #$PR_NUM](https://github.com/${GITHUB_REPOSITORY}/pull/$PR_NUM): $PR_TITLE by $AUTHOR\n"
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 ${{ github.ref }}^ 2>/dev/null || echo "")
|
||||
if [ -z "$PREV_TAG" ]; then
|
||||
RANGE=$(git rev-list --max-parents=0 HEAD)..HEAD
|
||||
else
|
||||
COMMIT_NOTES+="- [$SHA](https://github.com/${GITHUB_REPOSITORY}/commit/$SHA): $SHORT_MSG by $AUTHOR\n"
|
||||
RANGE=$PREV_TAG..HEAD
|
||||
fi
|
||||
done
|
||||
|
||||
NOTES="### Merged PRs\n$PR_NOTES\n### Direct commits\n$COMMIT_NOTES"
|
||||
|
||||
echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV
|
||||
echo -e "$NOTES" >> $GITHUB_ENV
|
||||
echo "EOF" >> $GITHUB_ENV
|
||||
echo "# Release ${{ github.ref_name }}" > release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
echo "## Changes since $PREV_TAG" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
git log $RANGE --pretty=format:"- %s ([%h](https://github.com/${{ github.repository }}/commit/%H)) by %an" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
|
|
@ -58,6 +47,6 @@ jobs:
|
|||
files: |
|
||||
noctalia-${{ github.ref_name }}.tar.gz
|
||||
noctalia-latest.tar.gz
|
||||
body: ${{ env.RELEASE_NOTES }}
|
||||
body_path: release_notes.md
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -1,120 +0,0 @@
|
|||
// Math helper functions for calculator functionality
|
||||
var MathHelper = {
|
||||
// Basic arithmetic operations
|
||||
add: (a, b) => a + b,
|
||||
subtract: (a, b) => a - b,
|
||||
multiply: (a, b) => a * b,
|
||||
divide: (a, b) => b !== 0 ? a / b : NaN,
|
||||
|
||||
// Power and roots
|
||||
pow: (base, exponent) => Math.pow(base, exponent),
|
||||
sqrt: (x) => x >= 0 ? Math.sqrt(x) : NaN,
|
||||
cbrt: (x) => Math.cbrt(x),
|
||||
|
||||
// Trigonometric functions (in radians)
|
||||
sin: (x) => Math.sin(x),
|
||||
cos: (x) => Math.cos(x),
|
||||
tan: (x) => Math.tan(x),
|
||||
asin: (x) => Math.asin(x),
|
||||
acos: (x) => Math.acos(x),
|
||||
atan: (x) => Math.atan(x),
|
||||
|
||||
// Logarithmic functions
|
||||
log: (x) => x > 0 ? Math.log(x) : NaN,
|
||||
log10: (x) => x > 0 ? Math.log10(x) : NaN,
|
||||
log2: (x) => x > 0 ? Math.log2(x) : NaN,
|
||||
|
||||
// Other mathematical functions
|
||||
abs: (x) => Math.abs(x),
|
||||
floor: (x) => Math.floor(x),
|
||||
ceil: (x) => Math.ceil(x),
|
||||
round: (x) => Math.round(x),
|
||||
min: (...args) => Math.min(...args),
|
||||
max: (...args) => Math.max(...args),
|
||||
|
||||
// Constants
|
||||
PI: Math.PI,
|
||||
E: Math.E,
|
||||
|
||||
// Factorial
|
||||
factorial: (n) => {
|
||||
if (n < 0 || n !== Math.floor(n)) return NaN;
|
||||
if (n === 0 || n === 1) return 1;
|
||||
let result = 1;
|
||||
for (let i = 2; i <= n; i++) {
|
||||
result *= i;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
// Percentage
|
||||
percent: (value, total) => (value / total) * 100,
|
||||
|
||||
// Degrees to radians and vice versa
|
||||
toRadians: (degrees) => degrees * (Math.PI / 180),
|
||||
toDegrees: (radians) => radians * (180 / Math.PI),
|
||||
|
||||
// Safe evaluation with math functions
|
||||
evaluate: (expression) => {
|
||||
try {
|
||||
// Replace common math functions with MathHelper equivalents
|
||||
let processedExpr = expression
|
||||
.replace(/\bpi\b/gi, 'MathHelper.PI')
|
||||
.replace(/\be\b/gi, 'MathHelper.E')
|
||||
.replace(/\bsin\b/gi, 'MathHelper.sin')
|
||||
.replace(/\bcos\b/gi, 'MathHelper.cos')
|
||||
.replace(/\btan\b/gi, 'MathHelper.tan')
|
||||
.replace(/\basin\b/gi, 'MathHelper.asin')
|
||||
.replace(/\bacos\b/gi, 'MathHelper.acos')
|
||||
.replace(/\batan\b/gi, 'MathHelper.atan')
|
||||
.replace(/\blog\b/gi, 'MathHelper.log')
|
||||
.replace(/\blog10\b/gi, 'MathHelper.log10')
|
||||
.replace(/\blog2\b/gi, 'MathHelper.log2')
|
||||
.replace(/\bsqrt\b/gi, 'MathHelper.sqrt')
|
||||
.replace(/\bcbrt\b/gi, 'MathHelper.cbrt')
|
||||
.replace(/\bpow\b/gi, 'MathHelper.pow')
|
||||
.replace(/\babs\b/gi, 'MathHelper.abs')
|
||||
.replace(/\bfloor\b/gi, 'MathHelper.floor')
|
||||
.replace(/\bceil\b/gi, 'MathHelper.ceil')
|
||||
.replace(/\bround\b/gi, 'MathHelper.round')
|
||||
.replace(/\bmin\b/gi, 'MathHelper.min')
|
||||
.replace(/\bmax\b/gi, 'MathHelper.max')
|
||||
.replace(/\bfactorial\b/gi, 'MathHelper.factorial')
|
||||
.replace(/\bpercent\b/gi, 'MathHelper.percent')
|
||||
.replace(/\btoRadians\b/gi, 'MathHelper.toRadians')
|
||||
.replace(/\btoDegrees\b/gi, 'MathHelper.toDegrees');
|
||||
|
||||
// Evaluate the expression
|
||||
const result = Function('MathHelper', 'return ' + processedExpr)(MathHelper);
|
||||
|
||||
// Check if result is valid
|
||||
if (isNaN(result) || !isFinite(result)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
// Format result for display
|
||||
formatResult: (result) => {
|
||||
if (result === null || isNaN(result) || !isFinite(result)) {
|
||||
return "Error";
|
||||
}
|
||||
|
||||
// For very large or small numbers, use scientific notation
|
||||
if (Math.abs(result) >= 1e10 || (Math.abs(result) < 1e-10 && result !== 0)) {
|
||||
return result.toExponential(6);
|
||||
}
|
||||
|
||||
// For integers, don't show decimal places
|
||||
if (Number.isInteger(result)) {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
// For decimals, limit to 8 significant digits
|
||||
return parseFloat(result.toPrecision(8)).toString();
|
||||
}
|
||||
};
|
||||
|
|
@ -11,7 +11,6 @@ import qs.Services
|
|||
import qs.Widgets
|
||||
|
||||
import "../../Helpers/FuzzySort.js" as Fuzzysort
|
||||
import "../../Helpers/MathHelper.js" as MathHelper
|
||||
|
||||
NLoader {
|
||||
id: appLauncher
|
||||
|
|
@ -188,26 +187,54 @@ NLoader {
|
|||
// Handle calculator
|
||||
if (query.startsWith(">calc")) {
|
||||
var expr = searchText.slice(5).trim()
|
||||
if (expr && isMathExpression(expr)) {
|
||||
var value = safeEval(expr)
|
||||
if (value !== null && value !== undefined && value !== "") {
|
||||
var formattedResult = MathHelper.MathHelper.formatResult(value)
|
||||
if (expr && expr !== "") {
|
||||
try {
|
||||
// Simple evaluation - only allow basic math operations
|
||||
var sanitizedExpr = expr.replace(/[^0-9+\-*/().\s]/g, '')
|
||||
var result = eval(sanitizedExpr)
|
||||
|
||||
if (isFinite(result) && !isNaN(result)) {
|
||||
var displayResult = Number.isInteger(result) ? result.toString() : result.toFixed(6).replace(/\.?0+$/, '')
|
||||
results.push({
|
||||
"isCalculator": true,
|
||||
"name": `Calculator: ${expr} = ${formattedResult}`,
|
||||
"result": value,
|
||||
"name": `${expr} = ${displayResult}`,
|
||||
"result": result,
|
||||
"expr": expr,
|
||||
"icon": "calculate",
|
||||
"execute": function () {
|
||||
Quickshell.clipboardText = String(formattedResult)
|
||||
clipboardTextCopyProcess.copyText(String(formattedResult))
|
||||
Quickshell.execDetached(
|
||||
["notify-send", "Calculator Result", `${expr} = ${formattedResult} (copied to clipboard)`])
|
||||
Quickshell.clipboardText = displayResult
|
||||
copyText(displayResult)
|
||||
Quickshell.execDetached(["notify-send", "Calculator", `${expr} = ${displayResult} (copied to clipboard)`])
|
||||
}
|
||||
})
|
||||
} else {
|
||||
results.push({
|
||||
"isCalculator": true,
|
||||
"name": "Invalid expression",
|
||||
"content": "Please enter a valid mathematical expression",
|
||||
"icon": "calculate",
|
||||
"execute": function () {}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
results.push({
|
||||
"isCalculator": true,
|
||||
"name": "Invalid expression",
|
||||
"content": "Please enter a valid mathematical expression",
|
||||
"icon": "calculate",
|
||||
"execute": function () {}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Show placeholder when just ">calc" is entered
|
||||
results.push({
|
||||
"isCalculator": true,
|
||||
"name": "Calculator",
|
||||
"content": "Enter a mathematical expression (e.g., 5+5, 2*3, 10/2)",
|
||||
"icon": "calculate",
|
||||
"execute": function () {}
|
||||
})
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
|
|
@ -240,14 +267,7 @@ NLoader {
|
|||
updateClipboardHistory()
|
||||
}
|
||||
|
||||
function isMathExpression(str) {
|
||||
// Allow more characters for enhanced math functions
|
||||
return /^[-+*/().0-9\s\w]+$/.test(str)
|
||||
}
|
||||
|
||||
function safeEval(expr) {
|
||||
return MathHelper.MathHelper.evaluate(expr)
|
||||
}
|
||||
|
||||
// Main content container
|
||||
Rectangle {
|
||||
|
|
|
|||
|
|
@ -550,9 +550,8 @@ WlSessionLock {
|
|||
height: 20 * scaling
|
||||
color: Color.mPrimary
|
||||
visible: passwordInput.activeFocus
|
||||
anchors.left: asterisksText.right
|
||||
anchors.leftMargin: Style.marginTiniest * scaling
|
||||
anchors.verticalCenter: asterisksText.verticalCenter
|
||||
Layout.leftMargin: asterisksText.width + Style.marginTiniest * scaling
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
SequentialAnimation on opacity {
|
||||
loops: Animation.Infinite
|
||||
|
|
@ -618,7 +617,7 @@ WlSessionLock {
|
|||
onClicked: lock.unlockAttempt()
|
||||
|
||||
SequentialAnimation on scale {
|
||||
running: containsMouse
|
||||
running: executeButtonArea.containsMouse
|
||||
NumberAnimation {
|
||||
to: 1.05
|
||||
duration: Style.animationFast
|
||||
|
|
@ -627,7 +626,7 @@ WlSessionLock {
|
|||
}
|
||||
|
||||
SequentialAnimation on scale {
|
||||
running: !containsMouse
|
||||
running: !executeButtonArea.containsMouse
|
||||
NumberAnimation {
|
||||
to: 1.0
|
||||
duration: Style.animationFast
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -78,6 +78,8 @@ A sleek, minimal, and thoughtfully crafted desktop shell for Wayland using **Qui
|
|||
- `matugen` - Material You color scheme generation
|
||||
- `cava` - Audio visualizer component
|
||||
- `gpu-screen-recorder` - Screen recording functionality
|
||||
- `brightnessctl` - For internal/laptop monitor brightness
|
||||
- `ddcutil` - For desktop monitor brightness
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -120,6 +122,8 @@ qs ipc call lockScreen toggle
|
|||
### Configuration
|
||||
|
||||
Access settings through the side panel (top right button) to configure weather, wallpapers, screen recording, audio, network, and theme options.
|
||||
Configuration is usually stored in ~/.config/noctalia
|
||||
If you upgrade from v1, you can delete the old configuration folder at ~/.config/Noctalia (with capital N)
|
||||
|
||||
### Application Launcher
|
||||
|
||||
|
|
@ -218,10 +222,11 @@ Noctalia/
|
|||
|
||||
### Contributing
|
||||
|
||||
1. Follow the existing code style and patterns
|
||||
2. Use the modular architecture for new features
|
||||
3. Implement proper error handling and logging
|
||||
4. Test with both Hyprland and Niri compositors (if applicable)
|
||||
1. All Pull requests should be based on the "dev" branch
|
||||
2. Follow the existing code style and patterns
|
||||
3. Use the modular architecture for new features
|
||||
4. Implement proper error handling and logging
|
||||
5. Test with both Hyprland and Niri compositors (if applicable)
|
||||
|
||||
Contributions are welcome! Don't worry about being perfect - every contribution helps! Whether it's fixing a small bug, adding a new feature, or improving documentation, we welcome all contributions. Feel free to open an issue to discuss ideas or ask questions before diving in. For feature requests and ideas, you can also use our discussions page.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue