switch to typescript on wails.io
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
auto-imports.d.ts
|
||||
components.d.ts
|
||||
3
app/.gitignore
vendored
Normal file
3
app/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
build/bin
|
||||
node_modules
|
||||
frontend/dist
|
||||
19
app/README.md
Normal file
19
app/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# README
|
||||
|
||||
## About
|
||||
|
||||
This is the official Wails Vue-TS template.
|
||||
|
||||
You can configure the project by editing `wails.json`. More information about the project settings can be found
|
||||
here: https://wails.io/docs/reference/project-config
|
||||
|
||||
## Live Development
|
||||
|
||||
To run in live development mode, run `wails dev` in the project directory. This will run a Vite development
|
||||
server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser
|
||||
and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect
|
||||
to this in your browser, and you can call your Go code from devtools.
|
||||
|
||||
## Building
|
||||
|
||||
To build a redistributable, production mode package, use `wails build`.
|
||||
7
app/Taskfile.yml
Normal file
7
app/Taskfile.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
version: "3"
|
||||
|
||||
tasks:
|
||||
dev:
|
||||
cmd: wails dev -tags webkit2_41
|
||||
# env:
|
||||
# WEBKIT_DISABLE_DMABUF_RENDERER: "1"
|
||||
27
app/app.go
Normal file
27
app/app.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// App struct
|
||||
type App struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewApp creates a new App application struct
|
||||
func NewApp() *App {
|
||||
return &App{}
|
||||
}
|
||||
|
||||
// startup is called when the app starts. The context is saved
|
||||
// so we can call the runtime methods
|
||||
func (a *App) startup(ctx context.Context) {
|
||||
a.ctx = ctx
|
||||
}
|
||||
|
||||
// Greet returns a greeting for the given name
|
||||
func (a *App) Greet(name string) string {
|
||||
return fmt.Sprintf("Hello %s, It's show time!", name)
|
||||
}
|
||||
35
app/build/README.md
Normal file
35
app/build/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Build Directory
|
||||
|
||||
The build directory is used to house all the build files and assets for your application.
|
||||
|
||||
The structure is:
|
||||
|
||||
* bin - Output directory
|
||||
* darwin - macOS specific files
|
||||
* windows - Windows specific files
|
||||
|
||||
## Mac
|
||||
|
||||
The `darwin` directory holds files specific to Mac builds.
|
||||
These may be customised and used as part of the build. To return these files to the default state, simply delete them
|
||||
and
|
||||
build with `wails build`.
|
||||
|
||||
The directory contains the following files:
|
||||
|
||||
- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`.
|
||||
- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`.
|
||||
|
||||
## Windows
|
||||
|
||||
The `windows` directory contains the manifest and rc files used when building with `wails build`.
|
||||
These may be customised for your application. To return these files to the default state, simply delete them and
|
||||
build with `wails build`.
|
||||
|
||||
- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to
|
||||
use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file
|
||||
will be created using the `appicon.png` file in the build directory.
|
||||
- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`.
|
||||
- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer,
|
||||
as well as the application itself (right click the exe -> properties -> details)
|
||||
- `wails.exe.manifest` - The main application manifest file.
|
||||
BIN
app/build/appicon.png
Normal file
BIN
app/build/appicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
68
app/build/darwin/Info.dev.plist
Normal file
68
app/build/darwin/Info.dev.plist
Normal file
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>{{.Info.ProductName}}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>{{.OutputFilename}}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.wails.{{.Name}}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{{.Info.ProductVersion}}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>{{.Info.Comments}}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{{.Info.ProductVersion}}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>iconfile</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.13.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>true</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>{{.Info.Copyright}}</string>
|
||||
{{if .Info.FileAssociations}}
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
{{range .Info.FileAssociations}}
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>{{.Ext}}</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>{{.Name}}</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>{{.Role}}</string>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>{{.IconName}}</string>
|
||||
</dict>
|
||||
{{end}}
|
||||
</array>
|
||||
{{end}}
|
||||
{{if .Info.Protocols}}
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
{{range .Info.Protocols}}
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.wails.{{.Scheme}}</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>{{.Scheme}}</string>
|
||||
</array>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>{{.Role}}</string>
|
||||
</dict>
|
||||
{{end}}
|
||||
</array>
|
||||
{{end}}
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
63
app/build/darwin/Info.plist
Normal file
63
app/build/darwin/Info.plist
Normal file
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>{{.Info.ProductName}}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>{{.OutputFilename}}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.wails.{{.Name}}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{{.Info.ProductVersion}}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>{{.Info.Comments}}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{{.Info.ProductVersion}}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>iconfile</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.13.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>true</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>{{.Info.Copyright}}</string>
|
||||
{{if .Info.FileAssociations}}
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
{{range .Info.FileAssociations}}
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>{{.Ext}}</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>{{.Name}}</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>{{.Role}}</string>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>{{.IconName}}</string>
|
||||
</dict>
|
||||
{{end}}
|
||||
</array>
|
||||
{{end}}
|
||||
{{if .Info.Protocols}}
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
{{range .Info.Protocols}}
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.wails.{{.Scheme}}</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>{{.Scheme}}</string>
|
||||
</array>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>{{.Role}}</string>
|
||||
</dict>
|
||||
{{end}}
|
||||
</array>
|
||||
{{end}}
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
app/build/windows/icon.ico
Normal file
BIN
app/build/windows/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
15
app/build/windows/info.json
Normal file
15
app/build/windows/info.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"fixed": {
|
||||
"file_version": "{{.Info.ProductVersion}}"
|
||||
},
|
||||
"info": {
|
||||
"0000": {
|
||||
"ProductVersion": "{{.Info.ProductVersion}}",
|
||||
"CompanyName": "{{.Info.CompanyName}}",
|
||||
"FileDescription": "{{.Info.ProductName}}",
|
||||
"LegalCopyright": "{{.Info.Copyright}}",
|
||||
"ProductName": "{{.Info.ProductName}}",
|
||||
"Comments": "{{.Info.Comments}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
114
app/build/windows/installer/project.nsi
Normal file
114
app/build/windows/installer/project.nsi
Normal file
@@ -0,0 +1,114 @@
|
||||
Unicode true
|
||||
|
||||
####
|
||||
## Please note: Template replacements don't work in this file. They are provided with default defines like
|
||||
## mentioned underneath.
|
||||
## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo.
|
||||
## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually
|
||||
## from outside of Wails for debugging and development of the installer.
|
||||
##
|
||||
## For development first make a wails nsis build to populate the "wails_tools.nsh":
|
||||
## > wails build --target windows/amd64 --nsis
|
||||
## Then you can call makensis on this file with specifying the path to your binary:
|
||||
## For a AMD64 only installer:
|
||||
## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe
|
||||
## For a ARM64 only installer:
|
||||
## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe
|
||||
## For a installer with both architectures:
|
||||
## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe
|
||||
####
|
||||
## The following information is taken from the ProjectInfo file, but they can be overwritten here.
|
||||
####
|
||||
## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}"
|
||||
## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}"
|
||||
## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}"
|
||||
## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}"
|
||||
## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}"
|
||||
###
|
||||
## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe"
|
||||
## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
|
||||
####
|
||||
## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html
|
||||
####
|
||||
## Include the wails tools
|
||||
####
|
||||
!include "wails_tools.nsh"
|
||||
|
||||
# The version information for this two must consist of 4 parts
|
||||
VIProductVersion "${INFO_PRODUCTVERSION}.0"
|
||||
VIFileVersion "${INFO_PRODUCTVERSION}.0"
|
||||
|
||||
VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}"
|
||||
VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer"
|
||||
VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}"
|
||||
VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}"
|
||||
VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}"
|
||||
VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}"
|
||||
|
||||
# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware
|
||||
ManifestDPIAware true
|
||||
|
||||
!include "MUI.nsh"
|
||||
|
||||
!define MUI_ICON "..\icon.ico"
|
||||
!define MUI_UNICON "..\icon.ico"
|
||||
# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314
|
||||
!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps
|
||||
!define MUI_ABORTWARNING # This will warn the user if they exit from the installer.
|
||||
|
||||
!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page.
|
||||
# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer
|
||||
!insertmacro MUI_PAGE_DIRECTORY # In which folder install page.
|
||||
!insertmacro MUI_PAGE_INSTFILES # Installing page.
|
||||
!insertmacro MUI_PAGE_FINISH # Finished installation page.
|
||||
|
||||
!insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer
|
||||
|
||||
## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1
|
||||
#!uninstfinalize 'signtool --file "%1"'
|
||||
#!finalize 'signtool --file "%1"'
|
||||
|
||||
Name "${INFO_PRODUCTNAME}"
|
||||
OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file.
|
||||
InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder).
|
||||
ShowInstDetails show # This will always show the installation details.
|
||||
|
||||
Function .onInit
|
||||
!insertmacro wails.checkArchitecture
|
||||
FunctionEnd
|
||||
|
||||
Section
|
||||
!insertmacro wails.setShellContext
|
||||
|
||||
!insertmacro wails.webview2runtime
|
||||
|
||||
SetOutPath $INSTDIR
|
||||
|
||||
!insertmacro wails.files
|
||||
|
||||
CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
|
||||
CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
|
||||
|
||||
!insertmacro wails.associateFiles
|
||||
!insertmacro wails.associateCustomProtocols
|
||||
|
||||
!insertmacro wails.writeUninstaller
|
||||
SectionEnd
|
||||
|
||||
Section "uninstall"
|
||||
!insertmacro wails.setShellContext
|
||||
|
||||
RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath
|
||||
|
||||
RMDir /r $INSTDIR
|
||||
|
||||
Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk"
|
||||
Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"
|
||||
|
||||
!insertmacro wails.unassociateFiles
|
||||
!insertmacro wails.unassociateCustomProtocols
|
||||
|
||||
!insertmacro wails.deleteUninstaller
|
||||
SectionEnd
|
||||
249
app/build/windows/installer/wails_tools.nsh
Normal file
249
app/build/windows/installer/wails_tools.nsh
Normal file
@@ -0,0 +1,249 @@
|
||||
# DO NOT EDIT - Generated automatically by `wails build`
|
||||
|
||||
!include "x64.nsh"
|
||||
!include "WinVer.nsh"
|
||||
!include "FileFunc.nsh"
|
||||
|
||||
!ifndef INFO_PROJECTNAME
|
||||
!define INFO_PROJECTNAME "{{.Name}}"
|
||||
!endif
|
||||
!ifndef INFO_COMPANYNAME
|
||||
!define INFO_COMPANYNAME "{{.Info.CompanyName}}"
|
||||
!endif
|
||||
!ifndef INFO_PRODUCTNAME
|
||||
!define INFO_PRODUCTNAME "{{.Info.ProductName}}"
|
||||
!endif
|
||||
!ifndef INFO_PRODUCTVERSION
|
||||
!define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}"
|
||||
!endif
|
||||
!ifndef INFO_COPYRIGHT
|
||||
!define INFO_COPYRIGHT "{{.Info.Copyright}}"
|
||||
!endif
|
||||
!ifndef PRODUCT_EXECUTABLE
|
||||
!define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
|
||||
!endif
|
||||
!ifndef UNINST_KEY_NAME
|
||||
!define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
|
||||
!endif
|
||||
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}"
|
||||
|
||||
!ifndef REQUEST_EXECUTION_LEVEL
|
||||
!define REQUEST_EXECUTION_LEVEL "admin"
|
||||
!endif
|
||||
|
||||
RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
|
||||
|
||||
!ifdef ARG_WAILS_AMD64_BINARY
|
||||
!define SUPPORTS_AMD64
|
||||
!endif
|
||||
|
||||
!ifdef ARG_WAILS_ARM64_BINARY
|
||||
!define SUPPORTS_ARM64
|
||||
!endif
|
||||
|
||||
!ifdef SUPPORTS_AMD64
|
||||
!ifdef SUPPORTS_ARM64
|
||||
!define ARCH "amd64_arm64"
|
||||
!else
|
||||
!define ARCH "amd64"
|
||||
!endif
|
||||
!else
|
||||
!ifdef SUPPORTS_ARM64
|
||||
!define ARCH "arm64"
|
||||
!else
|
||||
!error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY"
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!macro wails.checkArchitecture
|
||||
!ifndef WAILS_WIN10_REQUIRED
|
||||
!define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later."
|
||||
!endif
|
||||
|
||||
!ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED
|
||||
!define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}"
|
||||
!endif
|
||||
|
||||
${If} ${AtLeastWin10}
|
||||
!ifdef SUPPORTS_AMD64
|
||||
${if} ${IsNativeAMD64}
|
||||
Goto ok
|
||||
${EndIf}
|
||||
!endif
|
||||
|
||||
!ifdef SUPPORTS_ARM64
|
||||
${if} ${IsNativeARM64}
|
||||
Goto ok
|
||||
${EndIf}
|
||||
!endif
|
||||
|
||||
IfSilent silentArch notSilentArch
|
||||
silentArch:
|
||||
SetErrorLevel 65
|
||||
Abort
|
||||
notSilentArch:
|
||||
MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}"
|
||||
Quit
|
||||
${else}
|
||||
IfSilent silentWin notSilentWin
|
||||
silentWin:
|
||||
SetErrorLevel 64
|
||||
Abort
|
||||
notSilentWin:
|
||||
MessageBox MB_OK "${WAILS_WIN10_REQUIRED}"
|
||||
Quit
|
||||
${EndIf}
|
||||
|
||||
ok:
|
||||
!macroend
|
||||
|
||||
!macro wails.files
|
||||
!ifdef SUPPORTS_AMD64
|
||||
${if} ${IsNativeAMD64}
|
||||
File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}"
|
||||
${EndIf}
|
||||
!endif
|
||||
|
||||
!ifdef SUPPORTS_ARM64
|
||||
${if} ${IsNativeARM64}
|
||||
File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}"
|
||||
${EndIf}
|
||||
!endif
|
||||
!macroend
|
||||
|
||||
!macro wails.writeUninstaller
|
||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||
|
||||
SetRegView 64
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
|
||||
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
|
||||
|
||||
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
|
||||
IntFmt $0 "0x%08X" $0
|
||||
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
|
||||
!macroend
|
||||
|
||||
!macro wails.deleteUninstaller
|
||||
Delete "$INSTDIR\uninstall.exe"
|
||||
|
||||
SetRegView 64
|
||||
DeleteRegKey HKLM "${UNINST_KEY}"
|
||||
!macroend
|
||||
|
||||
!macro wails.setShellContext
|
||||
${If} ${REQUEST_EXECUTION_LEVEL} == "admin"
|
||||
SetShellVarContext all
|
||||
${else}
|
||||
SetShellVarContext current
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
# Install webview2 by launching the bootstrapper
|
||||
# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment
|
||||
!macro wails.webview2runtime
|
||||
!ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT
|
||||
!define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime"
|
||||
!endif
|
||||
|
||||
SetRegView 64
|
||||
# If the admin key exists and is not empty then webview2 is already installed
|
||||
ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
|
||||
${If} $0 != ""
|
||||
Goto ok
|
||||
${EndIf}
|
||||
|
||||
${If} ${REQUEST_EXECUTION_LEVEL} == "user"
|
||||
# If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed
|
||||
ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
|
||||
${If} $0 != ""
|
||||
Goto ok
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
SetDetailsPrint both
|
||||
DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}"
|
||||
SetDetailsPrint listonly
|
||||
|
||||
InitPluginsDir
|
||||
CreateDirectory "$pluginsdir\webview2bootstrapper"
|
||||
SetOutPath "$pluginsdir\webview2bootstrapper"
|
||||
File "tmp\MicrosoftEdgeWebview2Setup.exe"
|
||||
ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install'
|
||||
|
||||
SetDetailsPrint both
|
||||
ok:
|
||||
!macroend
|
||||
|
||||
# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b
|
||||
!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND
|
||||
; Backup the previously associated file class
|
||||
ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" ""
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0"
|
||||
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}"
|
||||
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}`
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}`
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open"
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}`
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}`
|
||||
!macroend
|
||||
|
||||
!macro APP_UNASSOCIATE EXT FILECLASS
|
||||
; Backup the previously associated file class
|
||||
ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup`
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0"
|
||||
|
||||
DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}`
|
||||
!macroend
|
||||
|
||||
!macro wails.associateFiles
|
||||
; Create file associations
|
||||
{{range .Info.FileAssociations}}
|
||||
!insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
|
||||
|
||||
File "..\{{.IconName}}.ico"
|
||||
{{end}}
|
||||
!macroend
|
||||
|
||||
!macro wails.unassociateFiles
|
||||
; Delete app associations
|
||||
{{range .Info.FileAssociations}}
|
||||
!insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}"
|
||||
|
||||
Delete "$INSTDIR\{{.IconName}}.ico"
|
||||
{{end}}
|
||||
!macroend
|
||||
|
||||
!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND
|
||||
DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}"
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" ""
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}"
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" ""
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" ""
|
||||
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}"
|
||||
!macroend
|
||||
|
||||
!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL
|
||||
DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
|
||||
!macroend
|
||||
|
||||
!macro wails.associateCustomProtocols
|
||||
; Create custom protocols associations
|
||||
{{range .Info.Protocols}}
|
||||
!insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
|
||||
|
||||
{{end}}
|
||||
!macroend
|
||||
|
||||
!macro wails.unassociateCustomProtocols
|
||||
; Delete app custom protocol associations
|
||||
{{range .Info.Protocols}}
|
||||
!insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}"
|
||||
{{end}}
|
||||
!macroend
|
||||
15
app/build/windows/wails.exe.manifest
Normal file
15
app/build/windows/wails.exe.manifest
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<assemblyIdentity type="win32" name="com.wails.{{.Name}}" version="{{.Info.ProductVersion}}.0" processorArchitecture="*"/>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- fallback for Windows 7 and 8 -->
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness> <!-- falls back to per-monitor if per-monitor v2 is not supported -->
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
||||
@@ -13,6 +13,7 @@
|
||||
"MaybeRefOrGetter": true,
|
||||
"PropType": true,
|
||||
"Ref": true,
|
||||
"ShallowRef": true,
|
||||
"Slot": true,
|
||||
"Slots": true,
|
||||
"VNode": true,
|
||||
@@ -26,18 +27,18 @@
|
||||
"effectScope": true,
|
||||
"getCurrentInstance": true,
|
||||
"getCurrentScope": true,
|
||||
"getCurrentWatcher": true,
|
||||
"h": true,
|
||||
"inject": true,
|
||||
"isProxy": true,
|
||||
"isReactive": true,
|
||||
"isReadonly": true,
|
||||
"isRef": true,
|
||||
"isShallow": true,
|
||||
"markRaw": true,
|
||||
"nextTick": true,
|
||||
"onActivated": true,
|
||||
"onBeforeMount": true,
|
||||
"onBeforeRouteLeave": true,
|
||||
"onBeforeRouteUpdate": true,
|
||||
"onBeforeUnmount": true,
|
||||
"onBeforeUpdate": true,
|
||||
"onDeactivated": true,
|
||||
@@ -70,8 +71,6 @@
|
||||
"useCssVars": true,
|
||||
"useId": true,
|
||||
"useModel": true,
|
||||
"useRoute": true,
|
||||
"useRouter": true,
|
||||
"useSlots": true,
|
||||
"useTemplateRef": true,
|
||||
"watch": true,
|
||||
13
app/frontend/index.html
Normal file
13
app/frontend/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>IrChad</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="./src/main.ts" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
7169
app/frontend/package-lock.json
generated
Normal file
7169
app/frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
36
app/frontend/package.json
Normal file
36
app/frontend/package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "irchad",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^5.2.9",
|
||||
"@mdi/font": "^7.4.47",
|
||||
"buffer": "^6.0.3",
|
||||
"irc-framework": "^4.14.0",
|
||||
"pinia": "^3.0.4",
|
||||
"vite-plugin-node-polyfills": "^0.25.0",
|
||||
"vue": "^3.2.37",
|
||||
"vuetify": "^3.11.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/types": "^7.18.10",
|
||||
"@tsconfig/node22": "^22.0.5",
|
||||
"@vitejs/plugin-vue": "^6.0.3",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-vuetify": "^4.3.5-beta.1",
|
||||
"sass-embedded": "^1.97.2",
|
||||
"typescript": "^5.9.3",
|
||||
"unplugin-auto-import": "^21.0.0",
|
||||
"unplugin-vue-components": "^31.0.0",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-vuetify": "^2.1.2",
|
||||
"vue-tsc": "^3.2.2"
|
||||
}
|
||||
}
|
||||
1
app/frontend/package.json.md5
Executable file
1
app/frontend/package.json.md5
Executable file
@@ -0,0 +1 @@
|
||||
d86c613036f8e3460cc743ac40acec6e
|
||||
14
app/frontend/src/App.vue
Normal file
14
app/frontend/src/App.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<Login v-if="!ircStore.connected" />
|
||||
<Chat v-else />
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useIRCStore } from "@/stores/irc";
|
||||
import Chat from "@/components/Chat.vue";
|
||||
import Login from "@/components/Login.vue";
|
||||
|
||||
const ircStore = useIRCStore();
|
||||
</script>
|
||||
@@ -1,7 +1,8 @@
|
||||
<script setup>
|
||||
import { useIRCStore } from "@/stores/irc";
|
||||
import { useBufferStore } from "@/stores/bufferStore";
|
||||
const { setActiveBuffer, buffers, activeBufferName } = useBufferStore();
|
||||
|
||||
const { setActiveBuffer, buffers, activeBufferName } = useIRCStore();
|
||||
const store = useBufferStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup>
|
||||
import { onMounted } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { useIRCStore } from "@/stores/irc";
|
||||
import { useBufferStore } from "@/stores/bufferStore";
|
||||
import { useAccountStore } from "@/stores/accountStore";
|
||||
|
||||
const store = useIRCStore();
|
||||
|
||||
onMounted(store.connect);
|
||||
const bufferStore = useBufferStore();
|
||||
const ircStore = useIRCStore();
|
||||
const accountStore = useAccountStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -17,13 +18,13 @@ onMounted(store.connect);
|
||||
<div class="messages d-flex flex-column">
|
||||
<v-toolbar density="compact">
|
||||
<v-toolbar-title>
|
||||
<p>{{ store.activeBufferName }}</p>
|
||||
{{ store.activeBuffer?.topic }}
|
||||
<p>{{ bufferStore.activeBufferName }}</p>
|
||||
{{ bufferStore.activeBuffer?.topic }}
|
||||
</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<MessageList
|
||||
:messages="store.activeBuffer?.messages"
|
||||
:me="store.clientInfo.nick"
|
||||
:messages="bufferStore.activeBuffer?.messages"
|
||||
:me="accountStore.account.nick"
|
||||
/>
|
||||
<v-sheet>
|
||||
<!-- <v-text-field -->
|
||||
@@ -35,11 +36,11 @@ onMounted(store.connect);
|
||||
<!-- @keydown.enter.exact.prevent="send" -->
|
||||
<!-- /> -->
|
||||
|
||||
<InputBuffer @send="store.sendActiveBuffer" />
|
||||
<InputBuffer @send="ircStore.sendActiveBuffer" />
|
||||
</v-sheet>
|
||||
</div>
|
||||
<v-sheet class="user-list h-100" border>
|
||||
<UserList :users="store.activeBuffer?.users" />
|
||||
<UserList :users="bufferStore.activeBuffer?.users" />
|
||||
</v-sheet>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,8 +1,11 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { useIRCStore } from "@/stores/irc";
|
||||
import { useBufferStore } from "@/stores/bufferStore";
|
||||
const emit = defineEmits(["send"]);
|
||||
|
||||
const store = useIRCStore();
|
||||
const bufferStore = useBufferStore();
|
||||
const text = ref();
|
||||
const menu = ref({
|
||||
open: false,
|
||||
@@ -26,6 +29,7 @@ const completionPos = ref(0);
|
||||
|
||||
function clickItem() {}
|
||||
function send() {
|
||||
if (!text.value) return;
|
||||
emit("send", text.value);
|
||||
menu.value.open = false;
|
||||
text.value = "";
|
||||
@@ -89,9 +93,12 @@ function tabComplete() {
|
||||
v-model="text"
|
||||
autofocus
|
||||
hide-details
|
||||
:placeholder="`Message ${bufferStore.activeBufferName}`"
|
||||
@input="trigger"
|
||||
@keydown.enter.prevent="send"
|
||||
@keydown.tab.prevent="tabComplete"
|
||||
variant="outlined"
|
||||
class="ma-1"
|
||||
role="irchad"
|
||||
></v-text-field>
|
||||
</template>
|
||||
56
app/frontend/src/components/Login.vue
Normal file
56
app/frontend/src/components/Login.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import { useAccountStore } from "@/stores/accountStore";
|
||||
import { useIRCStore } from "@/stores/irc";
|
||||
import { storeToRefs } from "pinia";
|
||||
const accountStore = useAccountStore();
|
||||
const ircStore = useIRCStore();
|
||||
|
||||
const { account } = storeToRefs(accountStore);
|
||||
const withAccount = ref(false);
|
||||
const form = ref(false);
|
||||
|
||||
function login() {
|
||||
ircStore.connect();
|
||||
}
|
||||
|
||||
function required(v: any) {
|
||||
return !!v || "This field is required";
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="w-25 mt-5 ma-auto">
|
||||
<v-card title="Login to IrChad">
|
||||
<v-form @submit.prevent="login" v-model="form">
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="account.nick"
|
||||
label="Nickname"
|
||||
:rules="[required]"
|
||||
/>
|
||||
<v-text-field
|
||||
v-if="withAccount"
|
||||
v-model="account.account"
|
||||
label="Username"
|
||||
role="username"
|
||||
:rules="[required]"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="account.password"
|
||||
v-if="withAccount"
|
||||
label="Password"
|
||||
type="password"
|
||||
:rules="[required]"
|
||||
/>
|
||||
<v-alert color="error" v-if="accountStore.authError.reason">
|
||||
{{ accountStore.authError.message }}
|
||||
</v-alert>
|
||||
<v-checkbox v-model="withAccount" label="Login with an account" />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn type="submit" color="success" :disabled="!form">Connect</v-btn>
|
||||
</v-card-actions>
|
||||
</v-form>
|
||||
</v-card>
|
||||
</main>
|
||||
</template>
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { computed, watch, useTemplateRef } from "vue";
|
||||
import { useIRCStore } from "@/stores/irc";
|
||||
const props = defineProps(["messages", "me"]);
|
||||
@@ -16,7 +16,7 @@ const timeFormatter = new Intl.DateTimeFormat("en-US", {
|
||||
hour12: true,
|
||||
});
|
||||
|
||||
function formatTime(ts) {
|
||||
function formatTime(ts: string) {
|
||||
const date = new Date(ts);
|
||||
return timeFormatter.format(date);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ watch(
|
||||
() => props.messages,
|
||||
() =>
|
||||
nextTick(() => {
|
||||
chatHistory.value.scrollTop = chatHistory.value.scrollHeight;
|
||||
chatHistory.value!.scrollTop = chatHistory.value!.scrollHeight;
|
||||
}),
|
||||
{ deep: true },
|
||||
);
|
||||
@@ -35,26 +35,27 @@ watch(
|
||||
<template>
|
||||
<v-sheet ref="chat-history" class="message-list d-flex">
|
||||
<div ref="chat-scrollback">
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="msg in messagesReverse"
|
||||
density="compact"
|
||||
:prepend-avatar="store.getMetadata(msg.nick, 'avatar')"
|
||||
<v-virtual-scroll height="100%" :items="messagesReverse">
|
||||
<template #default="{ item: msg }">
|
||||
<v-list-item
|
||||
density="compact"
|
||||
:prepend-avatar="store.getMetadata(msg.nick, 'avatar')"
|
||||
>
|
||||
<v-list-item-title>
|
||||
<span
|
||||
class="message-nick font-weight-bold"
|
||||
:class="{ 'text-primary': me === msg.nick }"
|
||||
>
|
||||
{{ msg.nick }}
|
||||
</span>
|
||||
<span class="message-time" v-if="!!msg.time">{{
|
||||
formatTime(msg.time)
|
||||
}}</span>
|
||||
</v-list-item-title>
|
||||
{{ msg.message }}
|
||||
</v-list-item></template
|
||||
>
|
||||
<v-list-item-title>
|
||||
<span
|
||||
class="message-nick font-weight-bold"
|
||||
:class="{ 'text-primary': me === msg.nick }"
|
||||
>
|
||||
{{ msg.nick }}
|
||||
</span>
|
||||
<span class="message-time" v-if="!!msg.time">{{
|
||||
formatTime(msg.time)
|
||||
}}</span>
|
||||
</v-list-item-title>
|
||||
{{ msg.message }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-virtual-scroll>
|
||||
</div>
|
||||
</v-sheet>
|
||||
</template>
|
||||
@@ -1,27 +1,30 @@
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useIRCStore } from "@/stores/irc";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useAccountStore } from "@/stores/accountStore";
|
||||
|
||||
const { selfAvatar } = storeToRefs(useIRCStore());
|
||||
const { clientInfo, setAvatar, setNick, setBio } = useIRCStore();
|
||||
const ircStore = useIRCStore();
|
||||
const accountStore = useAccountStore();
|
||||
const { selfAvatar } = storeToRefs(ircStore);
|
||||
const avatarDialog = ref(false);
|
||||
const newNick = ref();
|
||||
const newBio = ref();
|
||||
|
||||
function changeAvatar() {
|
||||
newNick.value = clientInfo.nick;
|
||||
newNick.value = accountStore.account.nick;
|
||||
avatarDialog.value = true;
|
||||
}
|
||||
|
||||
function submitAvatar() {
|
||||
setAvatar(selfAvatar.value);
|
||||
ircStore.setAvatar(selfAvatar.value);
|
||||
avatarDialog.value = false;
|
||||
if (newNick.value && clientInfo.nick !== newNick.value) {
|
||||
setNick(newNick.value);
|
||||
if (newNick.value && accountStore.account.nick !== newNick.value) {
|
||||
ircStore.setNick(newNick.value);
|
||||
}
|
||||
|
||||
if (newBio.value) {
|
||||
setBio(newBio.value);
|
||||
ircStore.setBio(newBio.value);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -42,7 +45,7 @@ function submitAvatar() {
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<v-avatar @click="changeAvatar" v-if="selfAvatar" :image="selfAvatar" />
|
||||
{{ clientInfo.nick }}
|
||||
{{ accountStore.account.nick }}
|
||||
</v-card-title>
|
||||
<v-card-text> </v-card-text>
|
||||
</v-card>
|
||||
@@ -1,16 +1,19 @@
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { useBufferStore } from "@/stores/bufferStore";
|
||||
import { useIRCStore } from "@/stores/irc";
|
||||
import { computed } from "vue";
|
||||
const props = defineProps(["users"]);
|
||||
const store = useIRCStore();
|
||||
const bufferStore = useBufferStore();
|
||||
|
||||
const sortedUsers = computed(() => {
|
||||
if (!props.users) return [];
|
||||
const u = [...props.users];
|
||||
if (!bufferStore.activeBuffer || !bufferStore.activeBuffer.users) return [];
|
||||
const u = [...bufferStore.activeBuffer.users];
|
||||
u.sort((a, b) => a.nick.localeCompare(b.nick));
|
||||
return u;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-list density="compact">
|
||||
<v-list-item
|
||||
51
app/frontend/src/lib/buffer.ts
Normal file
51
app/frontend/src/lib/buffer.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
import IrcChannel from "irc-framework/src/channel";
|
||||
import IrcUser from "irc-framework/src/user";
|
||||
|
||||
export interface BufferOptions {
|
||||
channel: typeof IrcChannel;
|
||||
name: string;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
export class Buffer {
|
||||
name: string;
|
||||
options: BufferOptions;
|
||||
channel: IrcChannel;
|
||||
metadata: Record<string, any>;
|
||||
lastSeenIdx: number;
|
||||
messages: any[];
|
||||
typing: string[];
|
||||
users: IrcUser[];
|
||||
topic: string | null;
|
||||
|
||||
constructor(options: BufferOptions) {
|
||||
this.options = options || null;
|
||||
|
||||
this.name = options.name;
|
||||
|
||||
this.channel = options.channel || null;
|
||||
|
||||
this.metadata = options.metadata || {};
|
||||
this.messages = [];
|
||||
this.lastSeenIdx = 0;
|
||||
|
||||
this.typing = [];
|
||||
this.topic = options.topic || null;
|
||||
|
||||
if (this.channel) this.syncUsers();
|
||||
}
|
||||
|
||||
syncUsers() {
|
||||
this.users = [...this.channel.users];
|
||||
}
|
||||
|
||||
kind() {
|
||||
return this.name.startsWith("#") ? "channel" : "pm";
|
||||
}
|
||||
|
||||
resetLastSeen() {
|
||||
this.lastSeenIdx = 0;
|
||||
}
|
||||
}
|
||||
16
app/frontend/src/main.ts
Normal file
16
app/frontend/src/main.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { registerPlugins } from "@/plugins";
|
||||
|
||||
// Components
|
||||
import App from "./App.vue";
|
||||
|
||||
// Composables
|
||||
import { createApp } from "vue";
|
||||
|
||||
// Styles
|
||||
// import "unfonts.css";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
registerPlugins(app);
|
||||
|
||||
app.mount("#app");
|
||||
8
app/frontend/src/plugins/index.ts
Normal file
8
app/frontend/src/plugins/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import vuetify from "./vuetify";
|
||||
import pinia from "@/stores";
|
||||
|
||||
import type { App } from "vue";
|
||||
|
||||
export function registerPlugins(app: App) {
|
||||
app.use(vuetify).use(pinia);
|
||||
}
|
||||
10
app/frontend/src/plugins/vuetify.ts
Normal file
10
app/frontend/src/plugins/vuetify.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import "@mdi/font/css/materialdesignicons.css";
|
||||
import "vuetify/styles";
|
||||
|
||||
import { createVuetify } from "vuetify";
|
||||
|
||||
export default createVuetify({
|
||||
theme: {
|
||||
defaultTheme: "system",
|
||||
},
|
||||
});
|
||||
25
app/frontend/src/stores/accountStore.ts
Normal file
25
app/frontend/src/stores/accountStore.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
|
||||
export const useAccountStore = defineStore("accountStore", () => {
|
||||
const authenticated = ref(false);
|
||||
const account = ref({
|
||||
nick: "",
|
||||
account: "",
|
||||
password: "",
|
||||
});
|
||||
|
||||
const authError = ref({
|
||||
reason: "",
|
||||
message: "",
|
||||
});
|
||||
|
||||
function setAuthenticated(v: boolean) {
|
||||
authenticated.value = v;
|
||||
}
|
||||
function setNick(v: string) {
|
||||
account.value.nick = v;
|
||||
}
|
||||
|
||||
return { account, authError, authenticated, setAuthenticated, setNick };
|
||||
});
|
||||
47
app/frontend/src/stores/bufferStore.ts
Normal file
47
app/frontend/src/stores/bufferStore.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Buffer, type BufferOptions } from "@/lib/buffer.ts";
|
||||
import { defineStore } from "pinia";
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
export const useBufferStore = defineStore("bufferStore", () => {
|
||||
const buffers = ref({} as Record<string, Buffer>);
|
||||
|
||||
const activeBufferName = ref(null as string | null);
|
||||
|
||||
function setActiveBuffer(bufferName: string) {
|
||||
const buffer = getBuffer(bufferName);
|
||||
if (!buffer) return;
|
||||
activeBufferName.value = bufferName;
|
||||
buffer.resetLastSeen();
|
||||
}
|
||||
|
||||
function addBuffer(bufferName: string, options: BufferOptions) {
|
||||
buffers.value[bufferName] = new Buffer(options);
|
||||
return buffers.value[bufferName];
|
||||
}
|
||||
|
||||
function getBuffer(bufferName: string) {
|
||||
return buffers.value[bufferName];
|
||||
}
|
||||
|
||||
function delBuffer(bufferName: string) {
|
||||
if (buffers.value[bufferName]) {
|
||||
delete buffers.value[bufferName];
|
||||
}
|
||||
}
|
||||
|
||||
const activeBuffer = computed(() => {
|
||||
if (activeBufferName.value) {
|
||||
return buffers.value[activeBufferName.value];
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
buffers,
|
||||
activeBufferName,
|
||||
activeBuffer,
|
||||
addBuffer,
|
||||
getBuffer,
|
||||
delBuffer,
|
||||
setActiveBuffer,
|
||||
};
|
||||
});
|
||||
3
app/frontend/src/stores/index.ts
Normal file
3
app/frontend/src/stores/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { createPinia } from "pinia";
|
||||
|
||||
export default createPinia();
|
||||
298
app/frontend/src/stores/irc.ts
Normal file
298
app/frontend/src/stores/irc.ts
Normal file
@@ -0,0 +1,298 @@
|
||||
import { defineStore, storeToRefs } from "pinia";
|
||||
import { Client } from "irc-framework";
|
||||
import { useBufferStore } from "./bufferStore";
|
||||
import { ref } from "vue";
|
||||
import { useAccountStore } from "./accountStore";
|
||||
|
||||
export const useIRCStore = defineStore("ircStore", () => {
|
||||
const bufferStore = useBufferStore();
|
||||
const accountStore = useAccountStore();
|
||||
const connected = ref(false);
|
||||
const { authError } = storeToRefs(accountStore);
|
||||
|
||||
const selfAvatar = ref("https://placekittens.com/128/128");
|
||||
const bio = ref();
|
||||
|
||||
loadPrefs();
|
||||
|
||||
function setAvatar(v: string) {
|
||||
selfAvatar.value = v;
|
||||
client.raw(`METADATA * SET avatar ${selfAvatar.value}`);
|
||||
storePrefs();
|
||||
}
|
||||
|
||||
function loadPrefs() {
|
||||
// const v = localStorage.getItem("prefs");
|
||||
// if (v === null) return;
|
||||
//
|
||||
// const prefs = JSON.parse(v);
|
||||
// if (!prefs) return;
|
||||
//
|
||||
// if (prefs.avatar) {
|
||||
// selfAvatar.value = prefs.avatar;
|
||||
// }
|
||||
//
|
||||
// if (prefs.nick) {
|
||||
// clientInfo.value.nick = prefs.nick;
|
||||
// }
|
||||
//
|
||||
// if (prefs.bio) {
|
||||
// bio.value = prefs.bio;
|
||||
// }
|
||||
}
|
||||
|
||||
function storePrefs() {
|
||||
// localStorage.setItem(
|
||||
// "prefs",
|
||||
// JSON.stringify({
|
||||
// nick: clientInfo.value.nick,
|
||||
// avatar: selfAvatar.value,
|
||||
// bio: bio.value,
|
||||
// }),
|
||||
// );
|
||||
}
|
||||
|
||||
function setNick(v: string) {
|
||||
client.changeNick(v);
|
||||
}
|
||||
|
||||
const metadata = ref({} as Record<string, any>);
|
||||
|
||||
function getMetadata(subject: string, key: string) {
|
||||
if (metadata.value[subject]) return metadata.value[subject][key];
|
||||
}
|
||||
|
||||
const client = markRaw(new Client());
|
||||
|
||||
function connect() {
|
||||
client.requestCap("draft/metadata-2");
|
||||
client.requestCap("echo-message");
|
||||
client.requestCap("chathistory");
|
||||
const tls = location.protocol === "https:";
|
||||
const connectParams = {
|
||||
host: location.hostname,
|
||||
port: location.port,
|
||||
tls,
|
||||
version: "irchad on irc-framework",
|
||||
path: "/ws",
|
||||
account: accountStore.account.account
|
||||
? {
|
||||
account: accountStore.account.account,
|
||||
password: accountStore.account.password,
|
||||
}
|
||||
: undefined,
|
||||
sasl_disconect_on_fail: true,
|
||||
nick: accountStore.account.nick,
|
||||
};
|
||||
|
||||
console.log(connectParams);
|
||||
client.connect(connectParams);
|
||||
}
|
||||
|
||||
function sendActiveBuffer(message: string) {
|
||||
if (!bufferStore.activeBuffer) {
|
||||
return;
|
||||
}
|
||||
bufferStore.activeBuffer.channel.say(message);
|
||||
}
|
||||
|
||||
function isMe(target: string) {
|
||||
console.log(client.user.nick);
|
||||
return target === client.user.nick;
|
||||
}
|
||||
|
||||
function setBio(v: string) {
|
||||
bio.value = v;
|
||||
client.raw(`METADATA * SET bio ${bio.value}`);
|
||||
storePrefs();
|
||||
}
|
||||
|
||||
client.on("socket close", () => {
|
||||
connected.value = false;
|
||||
});
|
||||
|
||||
client.on("loggedin", () => {
|
||||
accountStore.setAuthenticated(true);
|
||||
authError.value = {
|
||||
reason: "",
|
||||
message: "",
|
||||
};
|
||||
});
|
||||
|
||||
client.on(
|
||||
"sasl failed",
|
||||
({ reason, message }: { reason: string; message: string }) => {
|
||||
authError.value = {
|
||||
reason,
|
||||
message,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
client.on("registered", function () {
|
||||
connected.value = true;
|
||||
client.list();
|
||||
client.raw("METADATA * SUB avatar");
|
||||
client.raw("METADATA * SUB bio");
|
||||
client.raw(`METADATA * SET avatar ${selfAvatar.value}`);
|
||||
client.raw(`METADATA * SET bio ${bio.value}`);
|
||||
});
|
||||
|
||||
client.on(
|
||||
"nick",
|
||||
function ({ nick, new_nick }: { nick: string; new_nick: string }) {
|
||||
if (nick === client.user.nick) {
|
||||
accountStore.setNick(new_nick);
|
||||
}
|
||||
for (let buffName in bufferStore.buffers.value) {
|
||||
const buff = bufferStore.getBuffer(buffName);
|
||||
if (!buff) {
|
||||
console.log(`${buffName} not found`);
|
||||
continue;
|
||||
}
|
||||
const idx = buff.users.findIndex((u) => u.nick === nick);
|
||||
if (idx === -1) {
|
||||
console.log(`${nick} not found in ${buffName}`);
|
||||
continue;
|
||||
}
|
||||
buff.users[idx].nick = new_nick;
|
||||
}
|
||||
metadata.value[new_nick] = { ...metadata.value[nick] };
|
||||
delete metadata.value[nick];
|
||||
},
|
||||
);
|
||||
|
||||
client.on(
|
||||
"unknown command",
|
||||
function (ircCommand: { command: string; params: string[] }) {
|
||||
if (ircCommand.command === "METADATA") {
|
||||
const from = ircCommand.params[0];
|
||||
const target = ircCommand.params[2];
|
||||
const key = ircCommand.params[1];
|
||||
const value = ircCommand.params[3];
|
||||
|
||||
let subject = target;
|
||||
if (target === "*") {
|
||||
subject = from;
|
||||
}
|
||||
if (!subject || !key || !value) return;
|
||||
|
||||
if (!metadata.value[subject]) {
|
||||
metadata.value[subject] = {};
|
||||
}
|
||||
|
||||
metadata.value[subject][key] = value;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
client.on("channel list", (channels: { channel: string }[]) =>
|
||||
channels.map((ch) => client.join(ch.channel)),
|
||||
);
|
||||
|
||||
client.on(
|
||||
"tagmsg",
|
||||
({
|
||||
nick,
|
||||
tags,
|
||||
target,
|
||||
}: {
|
||||
nick: string;
|
||||
tags: string[];
|
||||
target: string;
|
||||
}) => {
|
||||
console.log(nick, tags, target);
|
||||
},
|
||||
);
|
||||
|
||||
client.on("message", function (message: { nick: string; target: string }) {
|
||||
let buffer;
|
||||
if (message.nick === "HistServ") return;
|
||||
if (isMe(message.target)) {
|
||||
buffer = bufferStore.getBuffer(message.nick);
|
||||
} else {
|
||||
buffer = bufferStore.getBuffer(message.target);
|
||||
}
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.messages.push(message);
|
||||
|
||||
if (
|
||||
bufferStore.activeBuffer &&
|
||||
bufferStore.activeBuffer.name === buffer.name
|
||||
) {
|
||||
buffer.resetLastSeen();
|
||||
}
|
||||
});
|
||||
|
||||
client.on("join", ({ nick, channel }: { nick: string; channel: string }) => {
|
||||
if (isMe(nick)) {
|
||||
bufferStore.addBuffer(channel, {
|
||||
name: channel,
|
||||
channel: client.channel(channel),
|
||||
});
|
||||
if (!bufferStore.activeBuffer) {
|
||||
bufferStore.setActiveBuffer(channel);
|
||||
}
|
||||
client.raw("CHATHISTORY LATEST " + channel + " * 200");
|
||||
return;
|
||||
}
|
||||
|
||||
const buffer = bufferStore.getBuffer(channel);
|
||||
if (!buffer) return;
|
||||
buffer.syncUsers();
|
||||
buffer.users.push({
|
||||
nick: nick,
|
||||
});
|
||||
});
|
||||
|
||||
client.on("quit", function ({ nick }: { nick: string }) {
|
||||
for (let buff of Object.values(bufferStore.buffers)) {
|
||||
const idx = buff.users.findIndex((u) => u.nick === nick);
|
||||
if (idx === -1) continue;
|
||||
buff.users.splice(idx, 1);
|
||||
}
|
||||
});
|
||||
|
||||
client.on(
|
||||
"topic",
|
||||
({ topic, channel }: { topic: string; channel: string }) => {
|
||||
const buffer = bufferStore.getBuffer(channel);
|
||||
if (!buffer) return;
|
||||
buffer.topic = topic;
|
||||
},
|
||||
);
|
||||
client.on("part", ({ nick, channel }: { nick: string; channel: string }) => {
|
||||
if (isMe(nick)) {
|
||||
bufferStore.delBuffer(channel);
|
||||
}
|
||||
const buffer = bufferStore.getBuffer(channel);
|
||||
if (!buffer) return;
|
||||
const idx = buffer.users.findIndex((u) => u.nick === nick);
|
||||
if (idx === -1) return;
|
||||
|
||||
buffer.users.splice(idx, 1);
|
||||
});
|
||||
|
||||
client.on("userlist", (ev: { channel: string; users: any[] }) => {
|
||||
const buffer = bufferStore.getBuffer(ev.channel);
|
||||
if (!buffer) return;
|
||||
buffer.users = ev.users;
|
||||
});
|
||||
|
||||
return {
|
||||
connect,
|
||||
client,
|
||||
sendActiveBuffer,
|
||||
getMetadata,
|
||||
metadata,
|
||||
selfAvatar,
|
||||
setAvatar,
|
||||
setNick,
|
||||
setBio,
|
||||
bio,
|
||||
connected,
|
||||
};
|
||||
});
|
||||
26
app/frontend/src/style.css
Normal file
26
app/frontend/src/style.css
Normal file
@@ -0,0 +1,26 @@
|
||||
html {
|
||||
background-color: rgba(27, 38, 54, 1);
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Nunito";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local(""),
|
||||
url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100vh;
|
||||
text-align: center;
|
||||
}
|
||||
0
app/frontend/src/styles/settings.scss
Normal file
0
app/frontend/src/styles/settings.scss
Normal file
35
app/frontend/src/types/irc-framework.d.ts
vendored
Normal file
35
app/frontend/src/types/irc-framework.d.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
declare module "irc-framework" {
|
||||
export interface IrcUser {
|
||||
nick: string;
|
||||
ident?: string;
|
||||
hostname?: string;
|
||||
modes?: string[];
|
||||
[key: string]: any;
|
||||
}
|
||||
//
|
||||
// export class Client {
|
||||
// join(channel: string, key?: string);
|
||||
// constructor();
|
||||
// connect(options: any): void;
|
||||
// on(event: string, callback: (event: any) => void): void;
|
||||
// channel(name: string): IrcChannel;
|
||||
// changeNick(newNick: string);
|
||||
// say(target: string, message: string);
|
||||
// raw(v: string);
|
||||
// requestCap(cap: string);
|
||||
// list();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// declare module "irc-framework/src/channel" {
|
||||
// export class IrcChannel {
|
||||
// constructor(irc_client: Client, channel_name: string, key?: string);
|
||||
// name: string;
|
||||
// users: IrcUser[];
|
||||
// say(message: string): void;
|
||||
// notice(message: string): void;
|
||||
// part(message?: string): void;
|
||||
// join(key?: string): void;
|
||||
// mode(mode: string, param?: string): void;
|
||||
// }
|
||||
}
|
||||
7
app/frontend/src/vite-env.d.ts
vendored
Normal file
7
app/frontend/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type {DefineComponent} from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
14
app/frontend/tsconfig.app.json
Normal file
14
app/frontend/tsconfig.app.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
11
app/frontend/tsconfig.json
Normal file
11
app/frontend/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
20
app/frontend/tsconfig.node.json
Normal file
20
app/frontend/tsconfig.node.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "@tsconfig/node22/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"],
|
||||
"allowJs": true
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,47 @@
|
||||
// Plugins
|
||||
import Vue from "@vitejs/plugin-vue";
|
||||
import AutoImport from "unplugin-auto-import/vite";
|
||||
import Components from "unplugin-vue-components/vite";
|
||||
import Fonts from "unplugin-fonts/vite";
|
||||
import Layouts from "vite-plugin-vue-layouts-next";
|
||||
import Vue from "@vitejs/plugin-vue";
|
||||
import VueRouter from "unplugin-vue-router/vite";
|
||||
import { VueRouterAutoImports } from "unplugin-vue-router";
|
||||
import Vuetify, { transformAssetUrls } from "vite-plugin-vuetify";
|
||||
import { nodePolyfills } from "vite-plugin-node-polyfills";
|
||||
|
||||
// Utilities
|
||||
import { defineConfig } from "vite";
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
VueRouter(),
|
||||
Layouts(),
|
||||
Vue({
|
||||
template: { transformAssetUrls },
|
||||
}),
|
||||
// https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme
|
||||
AutoImport({
|
||||
imports: [
|
||||
"vue",
|
||||
{
|
||||
pinia: ["defineStore", "storeToRefs"],
|
||||
},
|
||||
],
|
||||
dts: "src/auto-imports.d.ts",
|
||||
eslintrc: {
|
||||
enabled: true,
|
||||
},
|
||||
vueTemplate: true,
|
||||
}),
|
||||
Components({
|
||||
dts: "src/components.d.ts",
|
||||
}),
|
||||
Vuetify({
|
||||
autoImport: true,
|
||||
styles: {
|
||||
configFile: "src/styles/settings.scss",
|
||||
},
|
||||
}),
|
||||
Components(),
|
||||
Fonts({
|
||||
google: {
|
||||
families: [
|
||||
{
|
||||
name: "Roboto",
|
||||
styles: "wght@100;300;400;500;700;900",
|
||||
},
|
||||
],
|
||||
nodePolyfills({
|
||||
globals: {
|
||||
Buffer: true,
|
||||
},
|
||||
}),
|
||||
AutoImport({
|
||||
imports: [
|
||||
"vue",
|
||||
VueRouterAutoImports,
|
||||
{
|
||||
pinia: ["defineStore", "storeToRefs"],
|
||||
},
|
||||
],
|
||||
eslintrc: {
|
||||
enabled: true,
|
||||
},
|
||||
vueTemplate: true,
|
||||
}),
|
||||
],
|
||||
optimizeDeps: {
|
||||
exclude: [
|
||||
"vuetify",
|
||||
"vue-router",
|
||||
"unplugin-vue-router/runtime",
|
||||
"unplugin-vue-router/data-loaders",
|
||||
"unplugin-vue-router/data-loaders/basic",
|
||||
],
|
||||
exclude: ["vuetify"],
|
||||
},
|
||||
define: { "process.env": {} },
|
||||
resolve: {
|
||||
4
app/frontend/wailsjs/go/main/App.d.ts
vendored
Executable file
4
app/frontend/wailsjs/go/main/App.d.ts
vendored
Executable file
@@ -0,0 +1,4 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function Greet(arg1:string):Promise<string>;
|
||||
7
app/frontend/wailsjs/go/main/App.js
Executable file
7
app/frontend/wailsjs/go/main/App.js
Executable file
@@ -0,0 +1,7 @@
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function Greet(arg1) {
|
||||
return window['go']['main']['App']['Greet'](arg1);
|
||||
}
|
||||
24
app/frontend/wailsjs/runtime/package.json
Normal file
24
app/frontend/wailsjs/runtime/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@wailsapp/runtime",
|
||||
"version": "2.0.0",
|
||||
"description": "Wails Javascript runtime library",
|
||||
"main": "runtime.js",
|
||||
"types": "runtime.d.ts",
|
||||
"scripts": {
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wailsapp/wails.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Wails",
|
||||
"Javascript",
|
||||
"Go"
|
||||
],
|
||||
"author": "Lea Anthony <lea.anthony@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/wailsapp/wails/issues"
|
||||
},
|
||||
"homepage": "https://github.com/wailsapp/wails#readme"
|
||||
}
|
||||
249
app/frontend/wailsjs/runtime/runtime.d.ts
vendored
Normal file
249
app/frontend/wailsjs/runtime/runtime.d.ts
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
export interface Position {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface Size {
|
||||
w: number;
|
||||
h: number;
|
||||
}
|
||||
|
||||
export interface Screen {
|
||||
isCurrent: boolean;
|
||||
isPrimary: boolean;
|
||||
width : number
|
||||
height : number
|
||||
}
|
||||
|
||||
// Environment information such as platform, buildtype, ...
|
||||
export interface EnvironmentInfo {
|
||||
buildType: string;
|
||||
platform: string;
|
||||
arch: string;
|
||||
}
|
||||
|
||||
// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
|
||||
// emits the given event. Optional data may be passed with the event.
|
||||
// This will trigger any event listeners.
|
||||
export function EventsEmit(eventName: string, ...data: any): void;
|
||||
|
||||
// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
|
||||
export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
|
||||
|
||||
// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
|
||||
// sets up a listener for the given event name, but will only trigger a given number times.
|
||||
export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
|
||||
|
||||
// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
|
||||
// sets up a listener for the given event name, but will only trigger once.
|
||||
export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
|
||||
|
||||
// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
|
||||
// unregisters the listener for the given event name.
|
||||
export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
|
||||
|
||||
// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
|
||||
// unregisters all listeners.
|
||||
export function EventsOffAll(): void;
|
||||
|
||||
// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
|
||||
// logs the given message as a raw message
|
||||
export function LogPrint(message: string): void;
|
||||
|
||||
// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
|
||||
// logs the given message at the `trace` log level.
|
||||
export function LogTrace(message: string): void;
|
||||
|
||||
// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
|
||||
// logs the given message at the `debug` log level.
|
||||
export function LogDebug(message: string): void;
|
||||
|
||||
// [LogError](https://wails.io/docs/reference/runtime/log#logerror)
|
||||
// logs the given message at the `error` log level.
|
||||
export function LogError(message: string): void;
|
||||
|
||||
// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
|
||||
// logs the given message at the `fatal` log level.
|
||||
// The application will quit after calling this method.
|
||||
export function LogFatal(message: string): void;
|
||||
|
||||
// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
|
||||
// logs the given message at the `info` log level.
|
||||
export function LogInfo(message: string): void;
|
||||
|
||||
// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
|
||||
// logs the given message at the `warning` log level.
|
||||
export function LogWarning(message: string): void;
|
||||
|
||||
// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
|
||||
// Forces a reload by the main application as well as connected browsers.
|
||||
export function WindowReload(): void;
|
||||
|
||||
// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
|
||||
// Reloads the application frontend.
|
||||
export function WindowReloadApp(): void;
|
||||
|
||||
// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
|
||||
// Sets the window AlwaysOnTop or not on top.
|
||||
export function WindowSetAlwaysOnTop(b: boolean): void;
|
||||
|
||||
// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
|
||||
// *Windows only*
|
||||
// Sets window theme to system default (dark/light).
|
||||
export function WindowSetSystemDefaultTheme(): void;
|
||||
|
||||
// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
|
||||
// *Windows only*
|
||||
// Sets window to light theme.
|
||||
export function WindowSetLightTheme(): void;
|
||||
|
||||
// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
|
||||
// *Windows only*
|
||||
// Sets window to dark theme.
|
||||
export function WindowSetDarkTheme(): void;
|
||||
|
||||
// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
|
||||
// Centers the window on the monitor the window is currently on.
|
||||
export function WindowCenter(): void;
|
||||
|
||||
// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
|
||||
// Sets the text in the window title bar.
|
||||
export function WindowSetTitle(title: string): void;
|
||||
|
||||
// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
|
||||
// Makes the window full screen.
|
||||
export function WindowFullscreen(): void;
|
||||
|
||||
// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
|
||||
// Restores the previous window dimensions and position prior to full screen.
|
||||
export function WindowUnfullscreen(): void;
|
||||
|
||||
// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
|
||||
// Returns the state of the window, i.e. whether the window is in full screen mode or not.
|
||||
export function WindowIsFullscreen(): Promise<boolean>;
|
||||
|
||||
// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
|
||||
// Sets the width and height of the window.
|
||||
export function WindowSetSize(width: number, height: number): void;
|
||||
|
||||
// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
|
||||
// Gets the width and height of the window.
|
||||
export function WindowGetSize(): Promise<Size>;
|
||||
|
||||
// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
|
||||
// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
|
||||
// Setting a size of 0,0 will disable this constraint.
|
||||
export function WindowSetMaxSize(width: number, height: number): void;
|
||||
|
||||
// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
|
||||
// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
|
||||
// Setting a size of 0,0 will disable this constraint.
|
||||
export function WindowSetMinSize(width: number, height: number): void;
|
||||
|
||||
// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
|
||||
// Sets the window position relative to the monitor the window is currently on.
|
||||
export function WindowSetPosition(x: number, y: number): void;
|
||||
|
||||
// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
|
||||
// Gets the window position relative to the monitor the window is currently on.
|
||||
export function WindowGetPosition(): Promise<Position>;
|
||||
|
||||
// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
|
||||
// Hides the window.
|
||||
export function WindowHide(): void;
|
||||
|
||||
// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
|
||||
// Shows the window, if it is currently hidden.
|
||||
export function WindowShow(): void;
|
||||
|
||||
// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
|
||||
// Maximises the window to fill the screen.
|
||||
export function WindowMaximise(): void;
|
||||
|
||||
// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
|
||||
// Toggles between Maximised and UnMaximised.
|
||||
export function WindowToggleMaximise(): void;
|
||||
|
||||
// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
|
||||
// Restores the window to the dimensions and position prior to maximising.
|
||||
export function WindowUnmaximise(): void;
|
||||
|
||||
// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
|
||||
// Returns the state of the window, i.e. whether the window is maximised or not.
|
||||
export function WindowIsMaximised(): Promise<boolean>;
|
||||
|
||||
// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
|
||||
// Minimises the window.
|
||||
export function WindowMinimise(): void;
|
||||
|
||||
// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
|
||||
// Restores the window to the dimensions and position prior to minimising.
|
||||
export function WindowUnminimise(): void;
|
||||
|
||||
// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
|
||||
// Returns the state of the window, i.e. whether the window is minimised or not.
|
||||
export function WindowIsMinimised(): Promise<boolean>;
|
||||
|
||||
// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
|
||||
// Returns the state of the window, i.e. whether the window is normal or not.
|
||||
export function WindowIsNormal(): Promise<boolean>;
|
||||
|
||||
// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
|
||||
// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
|
||||
export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
|
||||
|
||||
// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
|
||||
// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
|
||||
export function ScreenGetAll(): Promise<Screen[]>;
|
||||
|
||||
// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
|
||||
// Opens the given URL in the system browser.
|
||||
export function BrowserOpenURL(url: string): void;
|
||||
|
||||
// [Environment](https://wails.io/docs/reference/runtime/intro#environment)
|
||||
// Returns information about the environment
|
||||
export function Environment(): Promise<EnvironmentInfo>;
|
||||
|
||||
// [Quit](https://wails.io/docs/reference/runtime/intro#quit)
|
||||
// Quits the application.
|
||||
export function Quit(): void;
|
||||
|
||||
// [Hide](https://wails.io/docs/reference/runtime/intro#hide)
|
||||
// Hides the application.
|
||||
export function Hide(): void;
|
||||
|
||||
// [Show](https://wails.io/docs/reference/runtime/intro#show)
|
||||
// Shows the application.
|
||||
export function Show(): void;
|
||||
|
||||
// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
|
||||
// Returns the current text stored on clipboard
|
||||
export function ClipboardGetText(): Promise<string>;
|
||||
|
||||
// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
|
||||
// Sets a text on the clipboard
|
||||
export function ClipboardSetText(text: string): Promise<boolean>;
|
||||
|
||||
// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
|
||||
// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
||||
export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
|
||||
|
||||
// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
|
||||
// OnFileDropOff removes the drag and drop listeners and handlers.
|
||||
export function OnFileDropOff() :void
|
||||
|
||||
// Check if the file path resolver is available
|
||||
export function CanResolveFilePaths(): boolean;
|
||||
|
||||
// Resolves file paths for an array of files
|
||||
export function ResolveFilePaths(files: File[]): void
|
||||
242
app/frontend/wailsjs/runtime/runtime.js
Normal file
242
app/frontend/wailsjs/runtime/runtime.js
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
export function LogPrint(message) {
|
||||
window.runtime.LogPrint(message);
|
||||
}
|
||||
|
||||
export function LogTrace(message) {
|
||||
window.runtime.LogTrace(message);
|
||||
}
|
||||
|
||||
export function LogDebug(message) {
|
||||
window.runtime.LogDebug(message);
|
||||
}
|
||||
|
||||
export function LogInfo(message) {
|
||||
window.runtime.LogInfo(message);
|
||||
}
|
||||
|
||||
export function LogWarning(message) {
|
||||
window.runtime.LogWarning(message);
|
||||
}
|
||||
|
||||
export function LogError(message) {
|
||||
window.runtime.LogError(message);
|
||||
}
|
||||
|
||||
export function LogFatal(message) {
|
||||
window.runtime.LogFatal(message);
|
||||
}
|
||||
|
||||
export function EventsOnMultiple(eventName, callback, maxCallbacks) {
|
||||
return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
|
||||
}
|
||||
|
||||
export function EventsOn(eventName, callback) {
|
||||
return EventsOnMultiple(eventName, callback, -1);
|
||||
}
|
||||
|
||||
export function EventsOff(eventName, ...additionalEventNames) {
|
||||
return window.runtime.EventsOff(eventName, ...additionalEventNames);
|
||||
}
|
||||
|
||||
export function EventsOffAll() {
|
||||
return window.runtime.EventsOffAll();
|
||||
}
|
||||
|
||||
export function EventsOnce(eventName, callback) {
|
||||
return EventsOnMultiple(eventName, callback, 1);
|
||||
}
|
||||
|
||||
export function EventsEmit(eventName) {
|
||||
let args = [eventName].slice.call(arguments);
|
||||
return window.runtime.EventsEmit.apply(null, args);
|
||||
}
|
||||
|
||||
export function WindowReload() {
|
||||
window.runtime.WindowReload();
|
||||
}
|
||||
|
||||
export function WindowReloadApp() {
|
||||
window.runtime.WindowReloadApp();
|
||||
}
|
||||
|
||||
export function WindowSetAlwaysOnTop(b) {
|
||||
window.runtime.WindowSetAlwaysOnTop(b);
|
||||
}
|
||||
|
||||
export function WindowSetSystemDefaultTheme() {
|
||||
window.runtime.WindowSetSystemDefaultTheme();
|
||||
}
|
||||
|
||||
export function WindowSetLightTheme() {
|
||||
window.runtime.WindowSetLightTheme();
|
||||
}
|
||||
|
||||
export function WindowSetDarkTheme() {
|
||||
window.runtime.WindowSetDarkTheme();
|
||||
}
|
||||
|
||||
export function WindowCenter() {
|
||||
window.runtime.WindowCenter();
|
||||
}
|
||||
|
||||
export function WindowSetTitle(title) {
|
||||
window.runtime.WindowSetTitle(title);
|
||||
}
|
||||
|
||||
export function WindowFullscreen() {
|
||||
window.runtime.WindowFullscreen();
|
||||
}
|
||||
|
||||
export function WindowUnfullscreen() {
|
||||
window.runtime.WindowUnfullscreen();
|
||||
}
|
||||
|
||||
export function WindowIsFullscreen() {
|
||||
return window.runtime.WindowIsFullscreen();
|
||||
}
|
||||
|
||||
export function WindowGetSize() {
|
||||
return window.runtime.WindowGetSize();
|
||||
}
|
||||
|
||||
export function WindowSetSize(width, height) {
|
||||
window.runtime.WindowSetSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetMaxSize(width, height) {
|
||||
window.runtime.WindowSetMaxSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetMinSize(width, height) {
|
||||
window.runtime.WindowSetMinSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetPosition(x, y) {
|
||||
window.runtime.WindowSetPosition(x, y);
|
||||
}
|
||||
|
||||
export function WindowGetPosition() {
|
||||
return window.runtime.WindowGetPosition();
|
||||
}
|
||||
|
||||
export function WindowHide() {
|
||||
window.runtime.WindowHide();
|
||||
}
|
||||
|
||||
export function WindowShow() {
|
||||
window.runtime.WindowShow();
|
||||
}
|
||||
|
||||
export function WindowMaximise() {
|
||||
window.runtime.WindowMaximise();
|
||||
}
|
||||
|
||||
export function WindowToggleMaximise() {
|
||||
window.runtime.WindowToggleMaximise();
|
||||
}
|
||||
|
||||
export function WindowUnmaximise() {
|
||||
window.runtime.WindowUnmaximise();
|
||||
}
|
||||
|
||||
export function WindowIsMaximised() {
|
||||
return window.runtime.WindowIsMaximised();
|
||||
}
|
||||
|
||||
export function WindowMinimise() {
|
||||
window.runtime.WindowMinimise();
|
||||
}
|
||||
|
||||
export function WindowUnminimise() {
|
||||
window.runtime.WindowUnminimise();
|
||||
}
|
||||
|
||||
export function WindowSetBackgroundColour(R, G, B, A) {
|
||||
window.runtime.WindowSetBackgroundColour(R, G, B, A);
|
||||
}
|
||||
|
||||
export function ScreenGetAll() {
|
||||
return window.runtime.ScreenGetAll();
|
||||
}
|
||||
|
||||
export function WindowIsMinimised() {
|
||||
return window.runtime.WindowIsMinimised();
|
||||
}
|
||||
|
||||
export function WindowIsNormal() {
|
||||
return window.runtime.WindowIsNormal();
|
||||
}
|
||||
|
||||
export function BrowserOpenURL(url) {
|
||||
window.runtime.BrowserOpenURL(url);
|
||||
}
|
||||
|
||||
export function Environment() {
|
||||
return window.runtime.Environment();
|
||||
}
|
||||
|
||||
export function Quit() {
|
||||
window.runtime.Quit();
|
||||
}
|
||||
|
||||
export function Hide() {
|
||||
window.runtime.Hide();
|
||||
}
|
||||
|
||||
export function Show() {
|
||||
window.runtime.Show();
|
||||
}
|
||||
|
||||
export function ClipboardGetText() {
|
||||
return window.runtime.ClipboardGetText();
|
||||
}
|
||||
|
||||
export function ClipboardSetText(text) {
|
||||
return window.runtime.ClipboardSetText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||
*
|
||||
* @export
|
||||
* @callback OnFileDropCallback
|
||||
* @param {number} x - x coordinate of the drop
|
||||
* @param {number} y - y coordinate of the drop
|
||||
* @param {string[]} paths - A list of file paths.
|
||||
*/
|
||||
|
||||
/**
|
||||
* OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
||||
*
|
||||
* @export
|
||||
* @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||
* @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target)
|
||||
*/
|
||||
export function OnFileDrop(callback, useDropTarget) {
|
||||
return window.runtime.OnFileDrop(callback, useDropTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* OnFileDropOff removes the drag and drop listeners and handlers.
|
||||
*/
|
||||
export function OnFileDropOff() {
|
||||
return window.runtime.OnFileDropOff();
|
||||
}
|
||||
|
||||
export function CanResolveFilePaths() {
|
||||
return window.runtime.CanResolveFilePaths();
|
||||
}
|
||||
|
||||
export function ResolveFilePaths(files) {
|
||||
return window.runtime.ResolveFilePaths(files);
|
||||
}
|
||||
37
app/go.mod
Normal file
37
app/go.mod
Normal file
@@ -0,0 +1,37 @@
|
||||
module IrChad
|
||||
|
||||
go 1.23
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.11.0
|
||||
|
||||
require (
|
||||
github.com/bep/debounce v1.2.1 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/labstack/echo/v4 v4.13.3 // indirect
|
||||
github.com/labstack/gommon v0.4.2 // indirect
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
|
||||
github.com/leaanthony/gosod v1.0.4 // indirect
|
||||
github.com/leaanthony/slicer v1.6.0 // indirect
|
||||
github.com/leaanthony/u v1.1.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/samber/lo v1.49.1 // indirect
|
||||
github.com/tkrajina/go-reflector v0.5.8 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.22 // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
golang.org/x/crypto v0.33.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
)
|
||||
|
||||
// replace github.com/wailsapp/wails/v2 v2.11.0 => /home/sam/go/pkg/mod
|
||||
81
app/go.sum
Normal file
81
app/go.sum
Normal file
@@ -0,0 +1,81 @@
|
||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
|
||||
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
|
||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
|
||||
github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI=
|
||||
github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw=
|
||||
github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
|
||||
github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
|
||||
github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
|
||||
github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
|
||||
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
|
||||
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
|
||||
github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58=
|
||||
github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
github.com/wailsapp/wails/v2 v2.11.0 h1:seLacV8pqupq32IjS4Y7V8ucab0WZwtK6VvUVxSBtqQ=
|
||||
github.com/wailsapp/wails/v2 v2.11.0/go.mod h1:jrf0ZaM6+GBc1wRmXsM8cIvzlg0karYin3erahI4+0k=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
41
app/main.go
Normal file
41
app/main.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
)
|
||||
|
||||
//go:embed all:frontend/dist
|
||||
var assets embed.FS
|
||||
|
||||
func fixNvidiaOpenOnX11() {
|
||||
_ = os.Setenv("WEBKIT_DISABLE_DMABUF_RENDERER", "1")
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Create an instance of the app structure
|
||||
fixNvidiaOpenOnX11()
|
||||
app := NewApp()
|
||||
|
||||
// Create application with options
|
||||
err := wails.Run(&options.App{
|
||||
Title: "IrChad",
|
||||
Width: 1024,
|
||||
Height: 768,
|
||||
AssetServer: &assetserver.Options{
|
||||
Assets: assets,
|
||||
},
|
||||
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
|
||||
OnStartup: app.startup,
|
||||
Bind: []any{
|
||||
app,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
println("Error:", err.Error())
|
||||
}
|
||||
}
|
||||
6
app/package-lock.json
generated
Normal file
6
app/package-lock.json
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "IrChad",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
13
app/wails.json
Normal file
13
app/wails.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://wails.io/schemas/config.v2.json",
|
||||
"name": "IrChad",
|
||||
"outputfilename": "IrChad",
|
||||
"frontend:install": "npm install",
|
||||
"frontend:build": "npm run build",
|
||||
"frontend:dev:watcher": "npm run dev",
|
||||
"frontend:dev:serverUrl": "auto",
|
||||
"author": {
|
||||
"name": "",
|
||||
"email": ""
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
ergo:
|
||||
init: true
|
||||
|
||||
@@ -27,7 +27,7 @@ server:
|
||||
# 'rfc1459-strict'. we recommend leaving this value at its default;
|
||||
# however, note that changing it once the network is already up and running is
|
||||
# problematic.
|
||||
casemapping: "precis"
|
||||
casemapping: "permissive"
|
||||
|
||||
# enforce-utf8 controls whether the server will preemptively discard non-UTF8
|
||||
# messages (since they cannot be relayed to websocket clients), or will allow
|
||||
@@ -810,17 +810,17 @@ limits:
|
||||
# fakelag: prevents clients from spamming commands too rapidly
|
||||
fakelag:
|
||||
# whether to enforce fakelag
|
||||
enabled: true
|
||||
enabled: false
|
||||
|
||||
# time unit for counting command rates
|
||||
window: 1s
|
||||
|
||||
# clients can send this many commands without fakelag being imposed
|
||||
burst-limit: 5
|
||||
burst-limit: 1000
|
||||
|
||||
# once clients have exceeded their burst allowance, they can send only
|
||||
# this many commands per `window`:
|
||||
messages-per-window: 2
|
||||
messages-per-window: 10000
|
||||
|
||||
# client status resets to the default state if they go this long without
|
||||
# sending any commands:
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
not ie 11
|
||||
@@ -1,5 +0,0 @@
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
22
irchad-web/.gitignore
vendored
22
irchad-web/.gitignore
vendored
@@ -1,22 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>IrChad</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"baseUrl": "./",
|
||||
"moduleResolution": "bundler",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "irchad-web",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "5.2.7",
|
||||
"@mdi/font": "7.4.47",
|
||||
"irc-framework": "^4.14.0",
|
||||
"pinia": "^3.0.3",
|
||||
"vue": "^3.5.21",
|
||||
"vue-router": "^4.5.1",
|
||||
"vuetify": "^3.10.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint-config-vuetify": "^4.2.0",
|
||||
"sass-embedded": "^1.92.1",
|
||||
"unplugin-auto-import": "^19.3.0",
|
||||
"unplugin-fonts": "^1.4.0",
|
||||
"unplugin-vue-components": "^29.0.0",
|
||||
"unplugin-vue-router": "^0.15.0",
|
||||
"vite": "^7.1.5",
|
||||
"vite-plugin-vue-layouts-next": "^1.0.0",
|
||||
"vite-plugin-vuetify": "^2.1.2"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<router-view />
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
//
|
||||
</script>
|
||||
@@ -1,9 +0,0 @@
|
||||
<template>
|
||||
<v-main>
|
||||
<router-view />
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
//
|
||||
</script>
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* main.js
|
||||
*
|
||||
* Bootstraps Vuetify and other plugins then mounts the App`
|
||||
*/
|
||||
|
||||
// Plugins
|
||||
import { registerPlugins } from '@/plugins'
|
||||
|
||||
// Components
|
||||
import App from './App.vue'
|
||||
|
||||
// Composables
|
||||
import { createApp } from 'vue'
|
||||
|
||||
// Styles
|
||||
import 'unfonts.css'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
registerPlugins(app)
|
||||
|
||||
app.mount('#app')
|
||||
@@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<Chat />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
//
|
||||
</script>
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* plugins/index.js
|
||||
*
|
||||
* Automatically included in `./src/main.js`
|
||||
*/
|
||||
|
||||
// Plugins
|
||||
import vuetify from './vuetify'
|
||||
import pinia from '@/stores'
|
||||
import router from '@/router'
|
||||
|
||||
export function registerPlugins (app) {
|
||||
app
|
||||
.use(vuetify)
|
||||
.use(router)
|
||||
.use(pinia)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* plugins/vuetify.js
|
||||
*
|
||||
* Framework documentation: https://vuetifyjs.com`
|
||||
*/
|
||||
|
||||
// Styles
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
import 'vuetify/styles'
|
||||
|
||||
// Composables
|
||||
import { createVuetify } from 'vuetify'
|
||||
|
||||
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
|
||||
export default createVuetify({
|
||||
theme: {
|
||||
defaultTheme: 'system',
|
||||
},
|
||||
})
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* router/index.ts
|
||||
*
|
||||
* Automatic routes for `./src/pages/*.vue`
|
||||
*/
|
||||
|
||||
// Composables
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { setupLayouts } from 'virtual:generated-layouts'
|
||||
import { routes } from 'vue-router/auto-routes'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: setupLayouts(routes),
|
||||
})
|
||||
|
||||
// Workaround for https://github.com/vitejs/vite/issues/11804
|
||||
router.onError((err, to) => {
|
||||
if (err?.message?.includes?.('Failed to fetch dynamically imported module')) {
|
||||
if (localStorage.getItem('vuetify:dynamic-reload')) {
|
||||
console.error('Dynamic import error, reloading page did not fix it', err)
|
||||
} else {
|
||||
console.log('Reloading page to fix dynamic import error')
|
||||
localStorage.setItem('vuetify:dynamic-reload', 'true')
|
||||
location.assign(to.fullPath)
|
||||
}
|
||||
} else {
|
||||
console.error(err)
|
||||
}
|
||||
})
|
||||
|
||||
router.isReady().then(() => {
|
||||
localStorage.removeItem('vuetify:dynamic-reload')
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -1,8 +0,0 @@
|
||||
// Utilities
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useAppStore = defineStore('app', {
|
||||
state: () => ({
|
||||
//
|
||||
}),
|
||||
})
|
||||
@@ -1,4 +0,0 @@
|
||||
// Utilities
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
export default createPinia()
|
||||
@@ -1,252 +0,0 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { Client } from "irc-framework";
|
||||
|
||||
function autoNick() {
|
||||
const discriminiator = Math.round(Math.random() * 100);
|
||||
return `chad-${discriminiator}`;
|
||||
}
|
||||
|
||||
export const useIRCStore = defineStore("irc", () => {
|
||||
const clientInfo = ref({
|
||||
nick: autoNick(),
|
||||
username: "chad",
|
||||
gecos: "IrChad",
|
||||
});
|
||||
|
||||
const selfAvatar = ref("https://placekittens.com/128/128");
|
||||
|
||||
loadPrefs();
|
||||
|
||||
function setAvatar(v) {
|
||||
selfAvatar.value = v;
|
||||
client.raw(`METADATA * SET avatar ${selfAvatar.value}`);
|
||||
storePrefs();
|
||||
}
|
||||
|
||||
function loadPrefs() {
|
||||
const prefs = JSON.parse(localStorage.getItem("prefs"));
|
||||
if (!prefs) return;
|
||||
|
||||
if (prefs.avatar) {
|
||||
selfAvatar.value = prefs.avatar;
|
||||
}
|
||||
if (prefs.nick) {
|
||||
clientInfo.value.nick = prefs.nick;
|
||||
}
|
||||
}
|
||||
|
||||
function storePrefs() {
|
||||
localStorage.setItem(
|
||||
"prefs",
|
||||
JSON.stringify({
|
||||
nick: clientInfo.value.nick,
|
||||
avatar: selfAvatar.value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function setNick(v) {
|
||||
client.changeNick(v);
|
||||
}
|
||||
|
||||
const buffers = ref({});
|
||||
const activeBufferName = ref();
|
||||
const metadata = ref({});
|
||||
|
||||
const activeBuffer = computed(() => {
|
||||
if (activeBufferName.value) {
|
||||
return buffers.value[activeBufferName.value];
|
||||
}
|
||||
});
|
||||
|
||||
function getMetadata(subject, key) {
|
||||
if (metadata.value[subject]) return metadata.value[subject][key];
|
||||
}
|
||||
|
||||
function setActiveBuffer(bufferName) {
|
||||
activeBufferName.value = bufferName;
|
||||
resetBufferLastSeen(bufferName);
|
||||
}
|
||||
|
||||
function resetBufferLastSeen(bufferName) {
|
||||
const buffer = getBuffer(bufferName);
|
||||
if (!buffer) return;
|
||||
buffer.lastSeenIdx = buffer.messages.length;
|
||||
}
|
||||
|
||||
const client = new Client({
|
||||
enable_echomessage: true,
|
||||
});
|
||||
|
||||
function connect() {
|
||||
client.requestCap("draft/metadata-2");
|
||||
client.requestCap("echo-message");
|
||||
client.requestCap("chathistory");
|
||||
const tls = location.protocol === "https:";
|
||||
client.connect({
|
||||
...clientInfo.value,
|
||||
host: location.hostname,
|
||||
tls,
|
||||
port: location.port,
|
||||
version: "irchad irc-framework",
|
||||
path: "/ws",
|
||||
});
|
||||
}
|
||||
|
||||
function sendActiveBuffer(message) {
|
||||
client.say(activeBufferName.value, message);
|
||||
}
|
||||
|
||||
function isMe(target) {
|
||||
return target === clientInfo.value.nick;
|
||||
}
|
||||
|
||||
function addBuffer(bufferName) {
|
||||
buffers.value[bufferName] = {
|
||||
messages: [],
|
||||
topic: "",
|
||||
users: [],
|
||||
lastSeenIdx: 0,
|
||||
};
|
||||
return buffers.value[bufferName];
|
||||
}
|
||||
|
||||
function getBuffer(bufferName) {
|
||||
return buffers.value[bufferName];
|
||||
}
|
||||
|
||||
function delBuffer(bufferName) {
|
||||
if (buffers.value[bufferName]) {
|
||||
delete buffers.value[bufferName];
|
||||
}
|
||||
}
|
||||
|
||||
client.on("registered", function () {
|
||||
client.list();
|
||||
client.raw("METADATA * SUB avatar");
|
||||
client.raw(`METADATA * SET avatar ${selfAvatar.value}`);
|
||||
});
|
||||
|
||||
client.on("nick", function ({ nick, new_nick }) {
|
||||
if (nick === clientInfo.value.nick) {
|
||||
clientInfo.value.nick = new_nick;
|
||||
storePrefs();
|
||||
}
|
||||
for (let buff of Object.values(buffers.value)) {
|
||||
const idx = buff.users.findIndex((u) => u.nick === nick);
|
||||
if (idx === -1) continue;
|
||||
buff.users[idx].nick = new_nick;
|
||||
}
|
||||
metadata.value[new_nick] = { ...metadata.value[nick] };
|
||||
delete metadata.value[nick];
|
||||
});
|
||||
|
||||
client.on("unknown command", function (ircCommand) {
|
||||
if (ircCommand.command === "METADATA") {
|
||||
const from = ircCommand.params[0];
|
||||
const target = ircCommand.params[2];
|
||||
const key = ircCommand.params[1];
|
||||
const value = ircCommand.params[3];
|
||||
|
||||
let subject = target;
|
||||
if (target === "*") {
|
||||
subject = from;
|
||||
}
|
||||
|
||||
if (!metadata.value[subject]) {
|
||||
metadata.value[subject] = {};
|
||||
}
|
||||
|
||||
metadata.value[subject][key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
client.on("channel list", (channels) =>
|
||||
channels.map((ch) => client.join(ch.channel)),
|
||||
);
|
||||
|
||||
client.on("message", function (message) {
|
||||
let buffer;
|
||||
if (message.nick === "HistServ") return;
|
||||
if (isMe(message.target)) {
|
||||
buffer = getBuffer(message.nick);
|
||||
} else {
|
||||
buffer = getBuffer(message.target);
|
||||
}
|
||||
buffer.messages.push(message);
|
||||
|
||||
if (activeBufferName.value) {
|
||||
resetBufferLastSeen(activeBufferName.value);
|
||||
}
|
||||
});
|
||||
|
||||
client.on("join", (ev) => {
|
||||
const nick = ev.nick;
|
||||
const channel = ev.channel;
|
||||
if (isMe(nick)) {
|
||||
addBuffer(channel);
|
||||
if (!activeBufferName.value) {
|
||||
activeBufferName.value = channel;
|
||||
}
|
||||
client.raw("CHATHISTORY LATEST " + channel + " * 200");
|
||||
return;
|
||||
}
|
||||
|
||||
const buffer = getBuffer(channel);
|
||||
if (!buffer) return;
|
||||
buffer.users.push({
|
||||
nick: ev.nick,
|
||||
gecos: ev.gecos,
|
||||
hostname: ev.hostname,
|
||||
ident: ev.ident,
|
||||
});
|
||||
});
|
||||
|
||||
client.on("quit", function ({ nick }) {
|
||||
for (let buff of Object.values(buffers.value)) {
|
||||
const idx = buff.users.findIndex((u) => u.nick === nick);
|
||||
if (idx === -1) continue;
|
||||
buff.users.splice(idx, 1);
|
||||
}
|
||||
});
|
||||
|
||||
client.on("topic", ({ topic, channel }) => {
|
||||
const buffer = getBuffer(channel);
|
||||
if (!buffer) return;
|
||||
buffer.topic = topic;
|
||||
});
|
||||
|
||||
client.on("part", ({ nick, channel }) => {
|
||||
if (isMe(nick)) {
|
||||
delBuffer(channel);
|
||||
}
|
||||
const buffer = getBuffer(channel);
|
||||
if (!buffer) return;
|
||||
const idx = buffer.users.findIndex((u) => u.nick === nick);
|
||||
if (idx === -1) return;
|
||||
|
||||
buffer.users.splice(idx, 1);
|
||||
});
|
||||
|
||||
client.on("userlist", (ev) => {
|
||||
const buffer = getBuffer(ev.channel);
|
||||
if (!buffer) return;
|
||||
buffer.users = ev.users;
|
||||
});
|
||||
|
||||
return {
|
||||
clientInfo,
|
||||
connect,
|
||||
client,
|
||||
buffers,
|
||||
activeBufferName,
|
||||
activeBuffer,
|
||||
sendActiveBuffer,
|
||||
setActiveBuffer,
|
||||
getMetadata,
|
||||
metadata,
|
||||
selfAvatar,
|
||||
setAvatar,
|
||||
setNick,
|
||||
};
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* src/styles/settings.scss
|
||||
*
|
||||
* Configures SASS variables and Vuetify overwrites
|
||||
*/
|
||||
|
||||
// https://vuetifyjs.com/features/sass-variables/`
|
||||
// @use 'vuetify/settings' with (
|
||||
// $color-pack: false
|
||||
// );
|
||||
3081
irchad-web/yarn.lock
3081
irchad-web/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user