Compare commits

..

No commits in common. "master" and "v0.1.1" have entirely different histories.

16 changed files with 48 additions and 680 deletions

View File

@ -15,9 +15,6 @@ jobs:
run: echo "${LOCIP} gitea.comnenos" >> /etc/hosts run: echo "${LOCIP} gitea.comnenos" >> /etc/hosts
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install Build Dependencies - name: Install Build Dependencies
run: | run: |
@ -28,8 +25,7 @@ jobs:
fuse \ fuse \
libfuse2 \ libfuse2 \
python3 \ python3 \
python3-pip \ python3-pip
zip
- name: Install .NET SDK - name: Install .NET SDK
run: | run: |
@ -50,43 +46,38 @@ jobs:
./appimagetool.AppImage --appimage-extract ./appimagetool.AppImage --appimage-extract
# Create wrapper script that uses extracted version # Create wrapper script that uses extracted version
echo '#!/bin/bash' > /usr/local/bin/appimagetool cat > /usr/local/bin/appimagetool << 'EOF'
echo '/workspace/gmgauthier/notepad/squashfs-root/AppRun "$@"' >> /usr/local/bin/appimagetool #!/bin/bash
/workspace/gmgauthier/notepad/squashfs-root/AppRun "$@"
EOF
chmod +x /usr/local/bin/appimagetool chmod +x /usr/local/bin/appimagetool
- name: Build Packages - name: Build Linux Packages
run: | run: |
cd NotePad cd NotePad
python3 publish.py both python3 publish.py linux both
- name: Create Release Archive - name: Create Release Archive
run: | run: |
VERSION=${GITHUB_REF#refs/tags/} VERSION=${GITHUB_REF#refs/tags/}
VERSION_NUM=${VERSION#v} # Remove 'v' prefix (e.g., v0.1.4 -> 0.1.4)
mkdir -p release mkdir -p release
# Copy AppImage (if it exists) - use version from build # Copy AppImage (if it exists)
if [ -f publish/appimage/NotePad-${VERSION_NUM}-x86_64.AppImage ]; then if [ -f publish/appimage/NotePad-0.1.0-x86_64.AppImage ]; then
cp publish/appimage/NotePad-${VERSION_NUM}-x86_64.AppImage \ cp publish/appimage/NotePad-0.1.0-x86_64.AppImage \
release/NotePad-${VERSION}-x86_64.AppImage release/NotePad-${VERSION}-x86_64.AppImage
fi fi
# Copy Linux Tarball # Copy Tarball
cp publish/tarball/notepad-${VERSION_NUM}-linux-x64.tar.gz \ cp publish/tarball/notepad-0.1.0-linux-x64.tar.gz \
release/notepad-${VERSION}-linux-x64.tar.gz release/notepad-${VERSION}-linux-x64.tar.gz
# Create Windows zip
cd publish/win-x64
zip -r ../../release/notepad-${VERSION}-win-x64.zip .
cd ../..
# Generate checksums # Generate checksums
cd release cd release
if [ -f NotePad-${VERSION}-x86_64.AppImage ]; then if [ -f NotePad-${VERSION}-x86_64.AppImage ]; then
sha256sum NotePad-${VERSION}-x86_64.AppImage > NotePad-${VERSION}-x86_64.AppImage.sha256 sha256sum NotePad-${VERSION}-x86_64.AppImage > NotePad-${VERSION}-x86_64.AppImage.sha256
fi fi
sha256sum notepad-${VERSION}-linux-x64.tar.gz > notepad-${VERSION}-linux-x64.tar.gz.sha256 sha256sum notepad-${VERSION}-linux-x64.tar.gz > notepad-${VERSION}-linux-x64.tar.gz.sha256
sha256sum notepad-${VERSION}-win-x64.zip > notepad-${VERSION}-win-x64.zip.sha256
ls -lh # For debugging ls -lh # For debugging
- name: Create Release - name: Create Release
@ -95,21 +86,6 @@ jobs:
run: | run: |
VERSION=${GITHUB_REF#refs/tags/} VERSION=${GITHUB_REF#refs/tags/}
# Explicitly fetch the tag with annotation
echo "Fetching tag ${VERSION} with annotation..."
git fetch origin tag ${VERSION} --force
# Get the tag annotation message (not the commit message)
echo "Extracting tag annotation..."
TAG_MESSAGE=$(git cat-file tag ${VERSION} | sed '1,/^$/d')
echo "Tag annotation: ${TAG_MESSAGE}"
# Create release body
RELEASE_BODY=$(printf "%s\n\n## Downloads\n\n### Linux\n- **AppImage**: Portable, single-file executable (no installation needed)\n- **Tarball**: Extract and run \`sudo ./install.sh\` to install\n\n### Windows\n- **Zip**: Extract and run \`NotePad.exe\`" "$TAG_MESSAGE")
# Escape the full body for JSON
RELEASE_BODY_JSON=$(printf '%s' "$RELEASE_BODY" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
# Create release # Create release
curl -X POST "https://repos.gmgauthier.com/api/v1/repos/${GITHUB_REPOSITORY}/releases" \ curl -X POST "https://repos.gmgauthier.com/api/v1/repos/${GITHUB_REPOSITORY}/releases" \
-H "Authorization: token ${GITEA_TOKEN}" \ -H "Authorization: token ${GITEA_TOKEN}" \
@ -117,7 +93,7 @@ jobs:
-d "{ -d "{
\"tag_name\": \"${VERSION}\", \"tag_name\": \"${VERSION}\",
\"name\": \"NotePad ${VERSION}\", \"name\": \"NotePad ${VERSION}\",
\"body\": \"${RELEASE_BODY_JSON}\" \"body\": \"Release ${VERSION}\n\n## Linux Downloads\n- **AppImage**: Portable, single-file executable (no installation needed)\n- **Tarball**: Extract and run \`sudo ./install.sh\` to install\"
}" > release_response.json }" > release_response.json
RELEASE_ID=$(cat release_response.json | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2) RELEASE_ID=$(cat release_response.json | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
@ -135,24 +111,14 @@ jobs:
--data-binary @release/NotePad-${VERSION}-x86_64.AppImage.sha256 --data-binary @release/NotePad-${VERSION}-x86_64.AppImage.sha256
fi fi
# Upload Linux tarball # Upload tarball
curl -X POST "https://repos.gmgauthier.com/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=notepad-${VERSION}-linux-x64.tar.gz" \ curl -X POST "https://repos.gmgauthier.com/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=notepad-${VERSION}-linux-x64.tar.gz" \
-H "Authorization: token ${GITEA_TOKEN}" \ -H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/gzip" \ -H "Content-Type: application/gzip" \
--data-binary @release/notepad-${VERSION}-linux-x64.tar.gz --data-binary @release/notepad-${VERSION}-linux-x64.tar.gz
# Upload tarball checksum
curl -X POST "https://repos.gmgauthier.com/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=notepad-${VERSION}-linux-x64.tar.gz.sha256" \ curl -X POST "https://repos.gmgauthier.com/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=notepad-${VERSION}-linux-x64.tar.gz.sha256" \
-H "Authorization: token ${GITEA_TOKEN}" \ -H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: text/plain" \ -H "Content-Type: text/plain" \
--data-binary @release/notepad-${VERSION}-linux-x64.tar.gz.sha256 --data-binary @release/notepad-${VERSION}-linux-x64.tar.gz.sha256
# Upload Windows zip
curl -X POST "https://repos.gmgauthier.com/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=notepad-${VERSION}-win-x64.zip" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/zip" \
--data-binary @release/notepad-${VERSION}-win-x64.zip
curl -X POST "https://repos.gmgauthier.com/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=notepad-${VERSION}-win-x64.zip.sha256" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: text/plain" \
--data-binary @release/notepad-${VERSION}-win-x64.zip.sha256

3
.gitignore vendored
View File

@ -6,6 +6,3 @@ publish/
riderModule.iml riderModule.iml
/_ReSharper.Caches/ /_ReSharper.Caches/
poetry.lock poetry.lock
# ImageMagick artifacts
!_*

View File

@ -15,12 +15,7 @@ public partial class App : Application
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
string? fileToOpen = null; desktop.MainWindow = new MainWindow();
if (desktop.Args?.Length > 0)
{
fileToOpen = desktop.Args[0];
}
desktop.MainWindow = new MainWindow(fileToOpen);
} }
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();

View File

@ -4,27 +4,6 @@
Title="Untitled - Notepad" Title="Untitled - Notepad"
Width="600" Height="400"> Width="600" Height="400">
<Window.Styles>
<Style Selector="Menu">
<Setter Property="Background" Value="#D3D3D3"/>
</Style>
<Style Selector="MenuItem">
<Setter Property="Background" Value="#D3D3D3"/>
<Setter Property="Foreground" Value="Black"/>
</Style>
<Style Selector="MenuItem:pointerover /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="#A9A9A9"/>
</Style>
<Style Selector="MenuItem:open /template/ Popup#PART_Popup > Border">
<Setter Property="Background" Value="#D3D3D3"/>
<Setter Property="BorderBrush" Value="#A9A9A9"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style Selector="Separator">
<Setter Property="Background" Value="#A9A9A9"/>
</Style>
</Window.Styles>
<DockPanel> <DockPanel>
<!-- Menu Bar --> <!-- Menu Bar -->
<Menu DockPanel.Dock="Top"> <Menu DockPanel.Dock="Top">
@ -36,7 +15,7 @@
<Separator/> <Separator/>
<MenuItem Header="E_xit" Click="OnExitClick"/> <MenuItem Header="E_xit" Click="OnExitClick"/>
</MenuItem> </MenuItem>
<MenuItem Header="_Edit" x:Name="EditMenuItem"> <MenuItem Header="_Edit">
<MenuItem Header="_Undo" Click="OnUndoClick" InputGesture="Ctrl+Z"/> <MenuItem Header="_Undo" Click="OnUndoClick" InputGesture="Ctrl+Z"/>
<Separator/> <Separator/>
<MenuItem Header="Cu_t" Click="OnCutClick" InputGesture="Ctrl+X"/> <MenuItem Header="Cu_t" Click="OnCutClick" InputGesture="Ctrl+X"/>
@ -50,7 +29,7 @@
<MenuItem Header="F_ormat"> <MenuItem Header="F_ormat">
<MenuItem Header="_Word Wrap" x:Name="WordWrapMenuItem" Click="OnWordWrapToggle"> <MenuItem Header="_Word Wrap" x:Name="WordWrapMenuItem" Click="OnWordWrapToggle">
<MenuItem.Icon> <MenuItem.Icon>
<CheckBox x:Name="WordWrapCheckBox" IsChecked="False" IsHitTestVisible="False"/> <CheckBox x:Name="WordWrapCheckBox" IsChecked="True" IsHitTestVisible="False"/>
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
@ -64,7 +43,7 @@
<TextBox x:Name="EditorTextBox" <TextBox x:Name="EditorTextBox"
AcceptsReturn="True" AcceptsReturn="True"
AcceptsTab="True" AcceptsTab="True"
TextWrapping="NoWrap" TextWrapping="Wrap"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"
@ -73,9 +52,8 @@
Background="White" Background="White"
Foreground="Black" Foreground="Black"
CaretBrush="Black" CaretBrush="Black"
FontFamily="Courier New,Liberation Mono,Courier,monospace" FontFamily="Consolas,Courier New,monospace"
FontSize="13" FontSize="12">
ClearSelectionOnLostFocus="False">
<TextBox.Styles> <TextBox.Styles>
<Style Selector="TextBox"> <Style Selector="TextBox">
<Setter Property="Background" Value="White"/> <Setter Property="Background" Value="White"/>

View File

@ -17,11 +17,7 @@ namespace NotePad
private bool _isModified; private bool _isModified;
private string? _originalText; private string? _originalText;
public MainWindow() : this(null) public MainWindow()
{
}
public MainWindow(string? fileToOpen)
{ {
InitializeComponent(); InitializeComponent();
UpdateTitle(); UpdateTitle();
@ -30,30 +26,6 @@ namespace NotePad
textBox.TextChanged += OnTextChanged; textBox.TextChanged += OnTextChanged;
Closing += OnWindowClosing; Closing += OnWindowClosing;
if (!string.IsNullOrEmpty(fileToOpen) && File.Exists(fileToOpen))
{
_ = LoadFileAsync(fileToOpen);
}
}
private async Task LoadFileAsync(string filePath)
{
try
{
var text = await File.ReadAllTextAsync(filePath);
_currentFilePath = filePath;
_currentFileName = Path.GetFileName(filePath);
this.FindControl<TextBox>("EditorTextBox")!.Text = text;
_originalText = text;
_isModified = false;
UpdateTitle();
}
catch (Exception)
{
// Silently ignore file loading errors on startup
}
} }
private void UpdateTitle() private void UpdateTitle()
@ -294,17 +266,7 @@ namespace NotePad
var textBox = this.FindControl<TextBox>("EditorTextBox")!; var textBox = this.FindControl<TextBox>("EditorTextBox")!;
checkBox.IsChecked = !checkBox.IsChecked; checkBox.IsChecked = !checkBox.IsChecked;
textBox.TextWrapping = checkBox.IsChecked == true ? TextWrapping.Wrap : TextWrapping.NoWrap;
if (checkBox.IsChecked == true)
{
textBox.TextWrapping = TextWrapping.Wrap;
ScrollViewer.SetHorizontalScrollBarVisibility(textBox, Avalonia.Controls.Primitives.ScrollBarVisibility.Disabled);
}
else
{
textBox.TextWrapping = TextWrapping.NoWrap;
ScrollViewer.SetHorizontalScrollBarVisibility(textBox, Avalonia.Controls.Primitives.ScrollBarVisibility.Auto);
}
} }
// Edit Menu // Edit Menu

View File

@ -1,24 +1,21 @@
<?xml version='1.0' encoding='utf-8'?> <Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault> <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<ApplicationIcon>img\notepad-icon.ico</ApplicationIcon>
<Version>0.1.17</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.3.12" /> <PackageReference Include="Avalonia" Version="11.3.12"/>
<PackageReference Include="Avalonia.Desktop" Version="11.3.12" /> <PackageReference Include="Avalonia.Desktop" Version="11.3.12"/>
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.12" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.12"/>
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.12" /> <PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.12"/>
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.12"> <PackageReference Include="Avalonia.Diagnostics" Version="11.3.12">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets> <IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets> <PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,14 +5,13 @@
set -e set -e
APP_NAME="NotePad" APP_NAME="NotePad"
VERSION="${1:-0.1.0}" # Use first argument or default to 0.1.0 VERSION="0.1.0"
ARCH="x86_64" ARCH="x86_64"
# Directories # Directories
PUBLISH_DIR="../publish/linux-x64" PUBLISH_DIR="../publish/linux-x64"
APPDIR="NotePad.AppDir" APPDIR="NotePad.AppDir"
OUTPUT_DIR="../publish/appimage" OUTPUT_DIR="../publish/appimage"
ICON_SOURCE="img/notepad-icon.svg"
echo "============================================================" echo "============================================================"
echo "Building AppImage for $APP_NAME v$VERSION" echo "Building AppImage for $APP_NAME v$VERSION"
@ -48,14 +47,15 @@ Categories=Utility;TextEditor;
Terminal=false Terminal=false
EOF EOF
# Copy application icon # Create a simple icon (using text as placeholder - replace with actual icon)
echo "Copying application icon..." echo "Creating icon placeholder..."
if [ ! -f "$ICON_SOURCE" ]; then # This creates a simple SVG icon - you should replace with an actual icon
echo "❌ ERROR: Icon not found at $ICON_SOURCE" cat > "$APPDIR/usr/share/icons/hicolor/256x256/apps/notepad.svg" << EOF
exit 1 <svg width="256" height="256" xmlns="http://www.w3.org/2000/svg">
fi <rect width="256" height="256" fill="#4a90e2"/>
mkdir -p "$APPDIR/usr/share/icons/hicolor/scalable/apps" <text x="128" y="140" font-size="120" fill="white" text-anchor="middle" font-family="sans-serif">N</text>
cp "$ICON_SOURCE" "$APPDIR/usr/share/icons/hicolor/scalable/apps/notepad.svg" </svg>
EOF
# Create AppRun script # Create AppRun script
echo "Creating AppRun script..." echo "Creating AppRun script..."
@ -71,7 +71,7 @@ chmod +x "$APPDIR/AppRun"
# Copy desktop file and icon to root of AppDir # Copy desktop file and icon to root of AppDir
cp "$APPDIR/usr/share/applications/notepad.desktop" "$APPDIR/" cp "$APPDIR/usr/share/applications/notepad.desktop" "$APPDIR/"
cp "$APPDIR/usr/share/icons/hicolor/scalable/apps/notepad.svg" "$APPDIR/notepad.svg" cp "$APPDIR/usr/share/icons/hicolor/256x256/apps/notepad.svg" "$APPDIR/notepad.svg"
# Check for appimagetool # Check for appimagetool
if ! command -v appimagetool &> /dev/null; then if ! command -v appimagetool &> /dev/null; then

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

View File

@ -1,213 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="72pt"
height="72pt"
id="svg604">
<metadata
id="metadata45">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs606">
<linearGradient
id="linearGradient612">
<stop
id="stop613"
style="stop-color:#7fa8e3;stop-opacity:0.74117601"
offset="0" />
<stop
id="stop614"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="50.643887"
y1="5.3679295"
x2="35.752094"
y2="68.044357"
id="linearGradient615"
xlink:href="#linearGradient612"
gradientUnits="userSpaceOnUse"
spreadMethod="pad" />
</defs>
<path
d="M 12.8163,74.753 C 10.3856,73.6481 7.07107,70.1126 8.83884,65.2512 L 78.6656,20.8361 c 1.9888,1.7678 3.5356,3.2041 1.9888,7.0711 -1.1048,1.9887 -14.2527,46.6248 -14.4736,49.4975 -0.8839,3.0936 -3.425,6.8501 -7.6235,6.6291 -4.1984,-0.221 -42.6474,-8.6179 -45.741,-9.2808 z"
transform="matrix(1.114903,0,0,1.114903,-5.305332,-3.889256)"
id="path794"
style="fill-opacity:0.30147125;fill-rule:evenodd" />
<path
d="M 12.8163,74.753 C 10.3856,73.6481 7.07107,70.1126 8.83884,65.2512 9.72267,59.948 25.6326,13.1021 29.1682,10.8924 31.3778,8.90368 34.582,8.13026 39.1119,9.34561 c 3.7565,0.88389 37.565,9.72279 39.5537,11.49049 1.9888,1.7678 3.5356,3.2041 1.9888,7.0711 -1.1048,1.9887 -14.2527,46.6248 -14.4736,49.4975 -0.8839,3.0936 -3.425,6.8501 -7.6235,6.6291 -4.1984,-0.221 -42.6474,-8.6179 -45.741,-9.2808 z"
transform="matrix(1.114903,0,0,1.114903,-8.162471,-8.460684)"
id="path609"
style="fill:#3d4e67;fill-rule:evenodd" />
<path
d="M 17.8987,70.9965 C 15.3576,70.3336 11.7114,69.6706 13.0373,65.6932 15.468,55.9705 27.8424,18.6264 33.1456,13.986 c 1.2154,-1.1049 5.3033,-1.5468 13.0373,0.8839 8.8389,2.6516 26.7375,8.6178 28.5053,9.5017 1.7677,0.8839 2.4307,0.8839 1.1048,4.8614 -1.9887,3.9775 -10.8275,38.007 -13.0373,43.7522 -1.5467,4.088 -1.8782,5.9662 -4.5299,5.9662"
transform="matrix(1.114903,0,0,1.114903,-8.162471,-8.460684)"
id="path608"
style="fill:#ffffff;fill-rule:evenodd" />
<path
d="m 28.75,13.75 c 0,0 3.125,-6.25005 10.9375,-4.37505 C 47.5,11.25 78.125,19.375 77.8125,21.875 77.5,24.375 71.875,39.0625 71.5625,40.3125 71.25,41.5625 42.5,40.9375 31.5625,47.5 20.625,54.0625 12.5,59.6875 12.5,59.6875 c 0,0 11.25,-35 16.25,-45.9375 z"
transform="matrix(0.94678,0,0,0.94678,-0.480566,0.409517)"
id="path636"
style="fill:url(#linearGradient615);fill-rule:evenodd" />
<path
d="M 29.2429,15.8991 69.8423,26.6877"
transform="translate(1.135645,0.851736)"
id="path671"
style="fill:none;stroke:#42667e;stroke-width:1pt" />
<path
d="M 27.8233,19.306 67.8549,30.9464"
transform="matrix(0.999855,-0.01703691,0.01703691,0.999855,-0.705041,5.077353)"
id="path672"
style="fill:none;stroke:#42667e;stroke-width:1pt" />
<path
d="M 29.2429,15.8991 69.8423,26.6877"
transform="translate(-5.394323,17.0347)"
id="path673"
style="fill:none;stroke:#42667e;stroke-width:1pt" />
<path
d="M 29.2429,15.8991 69.8423,26.6877"
transform="translate(-11.35647,34.0694)"
id="path675"
style="fill:none;stroke:#42667e;stroke-width:1pt" />
<path
d="M 27.8233,19.306 67.8549,30.9464"
transform="matrix(0.999855,-0.01703691,0.01703691,0.999855,-13.19715,38.29502)"
id="path676"
style="fill:none;stroke:#42667e;stroke-width:1pt" />
<path
d="M 27.8233,19.306 67.8549,30.9464"
transform="matrix(0.999855,-0.01703691,0.01703691,0.999855,-7.235008,21.26032)"
id="path674"
style="fill:none;stroke:#42667e;stroke-width:1pt" />
<g
id="g666">
<path
d="m 44.8581,15.0473 c -3.4478,0 -5.1105,-2.5484 -5.1105,-6.38799 0,-3.83962 2.7983,-6.95584 6.2461,-6.95584 3.4478,0 4.5425,1.12884 4.5425,4.96845"
transform="matrix(0.948718,0,0,1,4.011168,0.567827)"
id="path667"
style="fill:none;stroke:#4f4f4f;stroke-width:2.875;stroke-linecap:round" />
<path
d="m 44.8581,14.7634 c -3.4478,0 -5.3944,-2.2645 -5.3944,-6.10409 0,-3.83962 2.7983,-7.807574 6.2461,-7.807574 3.4478,0 4.8264,1.980574 4.8264,5.820184"
transform="matrix(0.948718,0,0,1,4.011168,0.567827)"
id="path668"
style="fill:none;stroke:#c2c2c2;stroke-width:0.625;stroke-linecap:round" />
</g>
<use
transform="translate(10.788642,1.987381)"
id="use669"
x="0"
y="0"
width="90"
height="90"
xlink:href="#g666" />
<g
transform="matrix(0.69841,0,0,0.69841,31.4038,0.671206)"
id="g677">
<defs
id="defs611">
<linearGradient
id="linearGradient626">
<stop
id="stop627"
style="stop-color:#b5772d;stop-opacity:1"
offset="0" />
<stop
id="stop628"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient619">
<stop
id="stop620"
style="stop-color:#770000;stop-opacity:1"
offset="0" />
<stop
id="stop621"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="66.331696"
y1="23.212469"
x2="63.465496"
y2="20.962799"
id="linearGradient622"
xlink:href="#linearGradient619"
gradientUnits="userSpaceOnUse"
gradientTransform="scale(1.004516,0.995504)"
spreadMethod="pad" />
<linearGradient
x1="56.327614"
y1="43.377247"
x2="51.654526"
y2="39.762909"
id="linearGradient625"
xlink:href="#linearGradient626"
gradientUnits="userSpaceOnUse"
gradientTransform="scale(0.912664,1.095694)"
spreadMethod="pad" />
</defs>
<path
d="M 9.33685,82.1156 C 17.9129,79.7641 30.9112,77.5637 40.1097,71.8924 56.9851,62.0714 66.0118,41.6332 76.4551,25.5877 77.285,12.3086 64.1128,5.96872 59.1331,8.87345 46.4766,25.4722 37.5548,43.5235 23.4458,55.9725 19.0886,66.5542 9.12934,82.738 9.33685,82.1156 z"
transform="translate(3.814559,2.934275)"
id="path632"
style="fill-opacity:0.28318601;fill-rule:evenodd" />
<path
d="M 9.33685,82.1156 C 17.9129,79.7641 28.5638,74.9228 37.7623,69.2516 54.6377,59.4306 64.2512,38.4055 74.6945,22.36 75.5244,9.08092 64.1128,5.96872 59.1331,8.87345 46.4766,25.4722 37.5548,43.5235 23.4458,55.9725 19.0886,66.5542 9.12934,82.738 9.33685,82.1156 z"
id="path617"
style="fill-rule:evenodd" />
<path
d="m 71.9972,20.9076 c -1.729,2.4898 -3.4581,4.9796 -5.1871,7.4694 -2.2823,-5.3946 -4.9796,-8.0919 -11.8266,-8.7143 2.2132,-2.6973 4.4263,-5.3946 6.6395,-8.0919 5.5329,-0.6225 9.8209,4.1497 10.3742,9.3368 z"
id="path613"
style="fill:#be6d6d;fill-rule:evenodd" />
<path
d="m 54.776,20.9076 c 5.3946,-0.3458 9.1293,3.6656 11.2041,8.2994 -8.4377,13.6248 -15.423,27.0422 -29.6703,37.7622 0,0 -3.5272,-10.1668 -8.7143,-8.9218 6.432,-7.262 21.3709,-28.0104 27.1805,-37.1398 z"
id="path614"
style="fill:#ffbc24;fill-rule:evenodd" />
<path
d="m 27.0767,58.6698 c 4.6684,-0.2421 8.6106,5.3255 7.5732,8.7144 -2.0057,1.5215 -5.2562,3.0431 -7.2619,4.5646 -0.3458,-2.7664 -2.144,-4.9104 -6.0171,-4.5646 1.729,-2.974 3.9768,-5.7404 5.7058,-8.7144 z"
id="path615"
style="fill:#e9dbb9;fill-rule:evenodd" />
<path
d="m 21.7859,66.9692 c 3.5618,-0.8299 5.0488,2.6973 5.8096,4.7722 l -13.2791,6.017 7.4695,-10.7892 z"
id="path616"
style="fill:#586f93;fill-rule:evenodd" />
<path
d="m 71.9972,20.9076 c -1.729,2.4898 -3.4581,4.9796 -5.1871,7.4694 -2.2823,-5.3946 -4.9796,-8.0919 -11.8266,-8.7143 2.2132,-2.6973 4.4263,-5.3946 6.6395,-8.0919 5.5329,-0.6225 9.8209,4.1497 10.3742,9.3368 z"
id="path618"
style="fill:url(#linearGradient622);fill-rule:evenodd" />
<path
d="m 62.8679,12.1932 -5.3946,6.847 2.9048,1.0374 5.3946,-6.432 -2.9048,-1.4524 z"
id="path623"
style="fill:#ffffff;fill-rule:evenodd" />
<path
d="m 54.776,20.9076 c 5.3946,-0.3458 9.1293,3.6656 11.2041,8.2994 -8.4377,13.6248 -15.423,27.0422 -29.6703,37.7622 0,0 -3.5272,-10.1668 -8.7143,-8.9218 6.432,-7.262 21.3709,-28.0104 27.1805,-37.1398 z"
id="path624"
style="fill:url(#linearGradient625);fill-rule:evenodd" />
<path
d="m 29.6703,56.18 c 1.2449,0.7608 2.4898,1.5215 3.7347,2.2823 C 42.5344,47.6039 46.6841,36.5381 58.9257,24.6423 57.7499,23.8815 56.5742,23.1208 55.3984,22.36 48.0673,35.0857 39.6987,47.3965 29.6703,56.18 z"
id="path630"
style="fill:#ffffff;fill-rule:evenodd" />
<path
d="m 34.7538,67.2805 c 0.2074,-2.1786 -0.3113,-3.7348 -1.4525,-5.4984 -1.5215,3.3889 -3.873,5.8441 -7.1582,6.6395 -0.7262,0.6224 1.2449,1.9711 1.4524,3.216 1.8674,-1.1412 7.1583,-3.7347 7.1583,-4.3571 z"
id="path631"
style="fill:#9c7850;fill-rule:evenodd" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -8,8 +8,6 @@ APP_NAME="NotePad"
INSTALL_DIR="/opt/notepad" INSTALL_DIR="/opt/notepad"
BIN_LINK="/usr/local/bin/notepad" BIN_LINK="/usr/local/bin/notepad"
DESKTOP_FILE="/usr/share/applications/notepad.desktop" DESKTOP_FILE="/usr/share/applications/notepad.desktop"
ICON_DIR="/usr/share/icons/hicolor/scalable/apps"
ICON_FILE="$ICON_DIR/notepad.svg"
echo "============================================================" echo "============================================================"
echo "$APP_NAME Installer" echo "$APP_NAME Installer"
@ -43,11 +41,6 @@ chmod +x "$INSTALL_DIR/NotePad"
echo "→ Creating symlink: $BIN_LINK" echo "→ Creating symlink: $BIN_LINK"
ln -sf "$INSTALL_DIR/NotePad" "$BIN_LINK" ln -sf "$INSTALL_DIR/NotePad" "$BIN_LINK"
# Install icon
echo "→ Installing application icon..."
mkdir -p "$ICON_DIR"
cp "$SCRIPT_DIR/img/notepad-icon.svg" "$ICON_FILE"
# Create desktop entry # Create desktop entry
echo "→ Creating desktop entry..." echo "→ Creating desktop entry..."
cat > "$DESKTOP_FILE" << EOF cat > "$DESKTOP_FILE" << EOF
@ -55,19 +48,13 @@ cat > "$DESKTOP_FILE" << EOF
Name=NotePad Name=NotePad
Comment=Simple text editor Comment=Simple text editor
Exec=notepad %F Exec=notepad %F
Icon=notepad Icon=text-editor
Type=Application Type=Application
Categories=Utility;TextEditor; Categories=Utility;TextEditor;
Terminal=false Terminal=false
MimeType=text/plain; MimeType=text/plain;
EOF EOF
# Update icon cache if available
if command -v gtk-update-icon-cache &> /dev/null; then
echo "→ Updating icon cache..."
gtk-update-icon-cache -f -t /usr/share/icons/hicolor 2>/dev/null || true
fi
# Update desktop database if available # Update desktop database if available
if command -v update-desktop-database &> /dev/null; then if command -v update-desktop-database &> /dev/null; then
echo "→ Updating desktop database..." echo "→ Updating desktop database..."

View File

@ -9,30 +9,9 @@ import sys
import os import os
import shutil import shutil
import tarfile import tarfile
import xml.etree.ElementTree as ET
from pathlib import Path from pathlib import Path
def get_version():
"""Extract version from .csproj file"""
csproj_path = Path("NotePad.csproj")
if not csproj_path.exists():
print("⚠️ WARNING: NotePad.csproj not found. Using default version 0.1.0")
return "0.1.0"
try:
tree = ET.parse(csproj_path)
root = tree.getroot()
version_elem = root.find(".//Version")
if version_elem is not None and version_elem.text:
return version_elem.text
print("⚠️ WARNING: Version not found in .csproj. Using default version 0.1.0")
return "0.1.0"
except Exception as e:
print(f"⚠️ WARNING: Failed to parse .csproj: {e}. Using default version 0.1.0")
return "0.1.0"
def run_command(cmd, description): def run_command(cmd, description):
"""Run a shell command and print status""" """Run a shell command and print status"""
print(f"\n{'=' * 60}") print(f"\n{'=' * 60}")
@ -90,7 +69,7 @@ def build_windows_installer():
print(f"\n⚠️ WARNING: Failed to create installer: {e}") print(f"\n⚠️ WARNING: Failed to create installer: {e}")
def build_linux_tarball(version): def build_linux_tarball():
"""Create tar.gz archive with install script""" """Create tar.gz archive with install script"""
print(f"\n{'=' * 60}") print(f"\n{'=' * 60}")
print("Creating Linux tar.gz archive") print("Creating Linux tar.gz archive")
@ -121,13 +100,8 @@ def build_linux_tarball(version):
shutil.copy(script_path, temp_dir / "notepad" / script) shutil.copy(script_path, temp_dir / "notepad" / script)
os.chmod(temp_dir / "notepad" / script, 0o755) os.chmod(temp_dir / "notepad" / script, 0o755)
# Copy img directory (contains icon)
img_dir = Path("img")
if img_dir.exists():
shutil.copytree(img_dir, temp_dir / "notepad" / "img")
# Create tar.gz # Create tar.gz
tarball_path = tarball_dir / f"notepad-{version}-linux-x64.tar.gz" tarball_path = tarball_dir / "notepad-0.1.0-linux-x64.tar.gz"
with tarfile.open(tarball_path, "w:gz") as tar: with tarfile.open(tarball_path, "w:gz") as tar:
tar.add(temp_dir / "notepad", arcname="notepad") tar.add(temp_dir / "notepad", arcname="notepad")
@ -142,7 +116,7 @@ def build_linux_tarball(version):
print(f" sudo ./install.sh") print(f" sudo ./install.sh")
def build_linux_appimage(version): def build_linux_appimage():
"""Build Linux AppImage""" """Build Linux AppImage"""
build_script = Path("build-appimage.sh") build_script = Path("build-appimage.sh")
if not build_script.exists(): if not build_script.exists():
@ -151,7 +125,7 @@ def build_linux_appimage(version):
try: try:
result = subprocess.run( result = subprocess.run(
["bash", str(build_script), version], ["bash", str(build_script)],
capture_output=True, capture_output=True,
text=True text=True
) )
@ -216,11 +190,10 @@ def publish_platform(platform, linux_package='both'):
# Build Linux packages # Build Linux packages
if platform == 'linux': if platform == 'linux':
version = get_version()
if linux_package in ['appimage', 'both']: if linux_package in ['appimage', 'both']:
build_linux_appimage(version) build_linux_appimage()
if linux_package in ['tarball', 'both']: if linux_package in ['tarball', 'both']:
build_linux_tarball(version) build_linux_tarball()
def main(): def main():

137
README.md
View File

@ -1,137 +0,0 @@
# NotePad
A simple cross-platform text editor built with Avalonia UI and .NET 8.
| Windows | Linux |
|-----------------------------------------------------------------| ----- |
| ![Windows Screenshot](NotePad/img/notepad-screenshot-win11.png) | ![Linux Screenshot](NotePad/img/notepad-screenshot-linux.png) |
## Installation
### Linux
Download the latest release from the [releases page](https://repos.gmgauthier.com/gmgauthier/notepad/releases).
#### Option 1: AppImage (Recommended)
The AppImage is a portable, single-file executable that requires no installation.
```bash
# Download the AppImage
wget https://repos.gmgauthier.com/gmgauthier/notepad/releases/download/v0.1.3/NotePad-v0.1.3-x86_64.AppImage
# Make it executable
chmod +x NotePad-v0.1.3-x86_64.AppImage
# Run it
./NotePad-v0.1.3-x86_64.AppImage
```
#### Option 2: System Installation (Tarball)
For a traditional system-wide installation:
```bash
# Download and extract
wget https://repos.gmgauthier.com/gmgauthier/notepad/releases/download/v0.1.3/notepad-v0.1.3-linux-x64.tar.gz
tar -xzf notepad-v0.1.3-linux-x64.tar.gz
cd notepad
# Install (requires sudo)
sudo ./install.sh
```
This installs NotePad to `/opt/notepad` and creates:
- Command-line shortcut: `notepad`
- Desktop menu entry
To uninstall:
```bash
sudo /opt/notepad/uninstall.sh
```
### Windows
Download the latest release from the [releases page](https://repos.gmgauthier.com/gmgauthier/notepad/releases).
```powershell
# Download the zip file
# Extract notepad-v0.1.3-win-x64.zip
# Run NotePad.exe from the extracted folder
```
No installation required - just extract and run!
## Building from Source
### Prerequisites
- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)
- Python 3.12+
- (Linux only) `appimagetool` for AppImage builds
### Build Commands
```bash
cd NotePad
# Build for Linux only
python3 publish.py linux
# Build for Windows only
python3 publish.py windows
# Build for both platforms
python3 publish.py both
# Linux-specific package options
python3 publish.py linux appimage # AppImage only
python3 publish.py linux tarball # Tarball only
python3 publish.py linux both # Both packages
```
Build outputs are located in `../publish/`:
- Linux AppImage: `publish/appimage/`
- Linux Tarball: `publish/tarball/`
- Windows: `publish/win-x64/`
## Development
### Project Structure
```
NotePad/
├── NotePad/ # Main application
│ ├── App.axaml # Application XAML
│ ├── MainWindow.axaml # Main window UI
│ ├── Program.cs # Entry point
│ └── publish.py # Build script
├── .gitea/
│ └── workflows/
│ └── release.yaml # CI/CD workflow
└── README.md
```
### Running in Development
```bash
cd NotePad/NotePad
dotnet run
```
## License
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
For more information, please refer to <https://unlicense.org>
## Author
Greg Gauthier
## Acknowledgements
Okay, I'll admit it. This application was build with the assisance of Grok, and the Claude agent built into Jetbrains Rider.

View File

@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

View File

@ -1,113 +0,0 @@
#!/usr/bin/env python3
"""
Release script for NotePad
Automates version bumping, committing, tagging, and pushing
"""
import sys
import subprocess
import xml.etree.ElementTree as ET
from pathlib import Path
def run_command(cmd, description):
"""Run a command and handle errors"""
print(f"\n{description}...")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"❌ ERROR: {description} failed!")
print(f" {result.stderr}")
sys.exit(1)
if result.stdout.strip():
print(f" {result.stdout.strip()}")
return result
def update_version_in_csproj(version):
"""Update the version in NotePad.csproj"""
csproj_path = Path("NotePad/NotePad.csproj")
if not csproj_path.exists():
print(f"❌ ERROR: {csproj_path} not found!")
sys.exit(1)
print(f"\n→ Updating version to {version} in {csproj_path}...")
try:
tree = ET.parse(csproj_path)
root = tree.getroot()
version_elem = root.find(".//Version")
if version_elem is not None:
version_elem.text = version
else:
# Add Version element if it doesn't exist
property_group = root.find(".//PropertyGroup")
if property_group is not None:
version_elem = ET.SubElement(property_group, "Version")
version_elem.text = version
else:
print("❌ ERROR: Could not find PropertyGroup in .csproj")
sys.exit(1)
tree.write(csproj_path, encoding='utf-8', xml_declaration=True)
print(f" ✅ Version updated to {version}")
except Exception as e:
print(f"❌ ERROR: Failed to update .csproj: {e}")
sys.exit(1)
def main():
if len(sys.argv) < 2:
print("Usage: python3 make-release.py <version> [tag message]")
print("")
print("Examples:")
print(" python3 make-release.py v0.1.6")
print(" python3 make-release.py v0.1.6 'Added fireworks to launch animations'")
sys.exit(1)
version_tag = sys.argv[1]
# Remove 'v' prefix for .csproj version
version_num = version_tag.lstrip('v')
# Get tag message from remaining arguments
tag_message = ' '.join(sys.argv[2:]) if len(sys.argv) > 2 else f"Release {version_tag}"
print("=" * 60)
print(f"NotePad Release Script")
print("=" * 60)
print(f"Version: {version_tag}")
print(f"Tag message: {tag_message}")
print("=" * 60)
# Step 1: Update version in .csproj
update_version_in_csproj(version_num)
# Step 2: Commit the version update
commit_message = f"Incremented to version {version_tag}"
run_command(["git", "add", "NotePad/NotePad.csproj"], "Staging .csproj")
run_command(["git", "commit", "-m", commit_message], "Committing version update")
# Step 3: Push to origin master
run_command(["git", "push", "origin", "master"], "Pushing to origin master")
# Step 4: Create git tag
run_command(["git", "tag", "-a", version_tag, "-m", tag_message], f"Creating tag {version_tag}")
# Step 5: Push tag to origin
run_command(["git", "push", "origin", version_tag], f"Pushing tag {version_tag}")
print("\n" + "=" * 60)
print("✅ Release completed successfully!")
print("=" * 60)
print(f"\nThe CI/CD workflow should now build and publish {version_tag}")
print(f"Check your Gitea repository for the release.")
if __name__ == "__main__":
main()