new
This commit is contained in:
		| @@ -1,37 +0,0 @@ | ||||
| /** | ||||
|  ****************************************************************************** | ||||
|  * @file    config.go | ||||
|  * @author  MakerYang | ||||
|  ****************************************************************************** | ||||
|  */ | ||||
|  | ||||
| package Config | ||||
|  | ||||
| import ( | ||||
| 	"embed" | ||||
| 	"encoding/json" | ||||
| 	"golang.org/x/sync/errgroup" | ||||
| ) | ||||
|  | ||||
| var Get = &Data{} | ||||
|  | ||||
| type Data struct { | ||||
| 	Info struct { | ||||
| 		CompanyName    string `json:"companyName"` | ||||
| 		ProductName    string `json:"productName"` | ||||
| 		ProductVersion string `json:"productVersion"` | ||||
| 	} `json:"info"` | ||||
| 	Group errgroup.Group | ||||
| } | ||||
|  | ||||
| func Init(version embed.FS) { | ||||
| 	wails, _ := version.ReadFile("wails.json") | ||||
| 	var wailsJson Data | ||||
| 	err := json.Unmarshal(wails, &wailsJson) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	Get.Info.ProductVersion = wailsJson.Info.ProductVersion | ||||
| 	Get.Info.ProductName = wailsJson.Info.ProductName | ||||
| 	Get.Info.CompanyName = wailsJson.Info.CompanyName | ||||
| } | ||||
| @@ -1,62 +0,0 @@ | ||||
| /** | ||||
|  ****************************************************************************** | ||||
|  * @file    framework.go | ||||
|  * @author  MakerYang | ||||
|  ****************************************************************************** | ||||
|  */ | ||||
|  | ||||
| package Framework | ||||
|  | ||||
| import ( | ||||
| 	"cnc/framework/config" | ||||
| 	"cnc/framework/windows/start" | ||||
| 	"embed" | ||||
| 	"fmt" | ||||
| 	"github.com/gookit/color" | ||||
| 	"github.com/wailsapp/wails/v2" | ||||
| 	"github.com/wailsapp/wails/v2/pkg/options" | ||||
| 	"github.com/wailsapp/wails/v2/pkg/options/assetserver" | ||||
| 	"github.com/wailsapp/wails/v2/pkg/options/linux" | ||||
| 	"github.com/wailsapp/wails/v2/pkg/options/windows" | ||||
| ) | ||||
|  | ||||
| func Init(template embed.FS, version embed.FS) { | ||||
|  | ||||
| 	Config.Init(version) | ||||
|  | ||||
| 	start := StartWindows.Init() | ||||
|  | ||||
| 	err := wails.Run(&options.App{ | ||||
| 		Title:     "", | ||||
| 		Width:     1200, | ||||
| 		Height:    768, | ||||
| 		MinWidth:  1200, | ||||
| 		MinHeight: 768, | ||||
| 		AssetServer: &assetserver.Options{ | ||||
| 			Assets: template, | ||||
| 		}, | ||||
| 		BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 1}, | ||||
| 		OnStartup:        start.Startup, | ||||
| 		OnShutdown:       start.Shutdown, | ||||
| 		Bind: []interface{}{ | ||||
| 			start, | ||||
| 		}, | ||||
| 		WindowStartState: options.Normal, | ||||
| 		Windows: &windows.Options{ | ||||
| 			WebviewDisableRendererCodeIntegrity: true, | ||||
| 			DisableWindowIcon:                   true, | ||||
| 		}, | ||||
| 		Linux: &linux.Options{ | ||||
| 			Icon:                []byte(""), | ||||
| 			WindowIsTranslucent: false, | ||||
| 			WebviewGpuPolicy:    linux.WebviewGpuPolicyNever, | ||||
| 		}, | ||||
| 		Debug: options.Debug{ | ||||
| 			OpenInspectorOnStartup: false, | ||||
| 		}, | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		fmt.Println("[desktop][framework]:" + color.Gray.Text(err.Error())) | ||||
| 	} | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| /** | ||||
|  ****************************************************************************** | ||||
|  * @file    index.go | ||||
|  * @author  MakerYang | ||||
|  ****************************************************************************** | ||||
|  */ | ||||
|  | ||||
| package StartWindows | ||||
|  | ||||
| import ( | ||||
| 	"cnc/framework/config" | ||||
| 	"context" | ||||
| 	"os" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| type Api struct { | ||||
| 	ctx context.Context | ||||
| } | ||||
|  | ||||
| type ReturnResponse struct { | ||||
| 	Code int         `json:"code"` | ||||
| 	Data interface{} `json:"data"` | ||||
| 	Msg  string      `json:"msg"` | ||||
| } | ||||
|  | ||||
| func Init() *Api { | ||||
| 	return &Api{} | ||||
| } | ||||
|  | ||||
| func (start *Api) Startup(ctx context.Context) { | ||||
| 	start.ctx = ctx | ||||
| } | ||||
|  | ||||
| func (start *Api) Shutdown(ctx context.Context) { | ||||
|  | ||||
| } | ||||
|  | ||||
| func (start *Api) GetPlatform() string { | ||||
| 	platform := "" | ||||
| 	switch runtime.GOOS { | ||||
| 	case "windows": | ||||
| 		platform = "Windows" | ||||
| 	case "darwin": | ||||
| 		platform = "Darwin" | ||||
| 	case "linux": | ||||
| 		platform = "Linux" | ||||
| 		content, err := os.ReadFile("/etc/os-release") | ||||
| 		if err == nil { | ||||
| 			lines := strings.Split(string(content), "\n") | ||||
| 			for _, line := range lines { | ||||
| 				if strings.HasPrefix(line, "ID=") { | ||||
| 					switch { | ||||
| 					case strings.Contains(line, "ubuntu"): | ||||
| 						platform = "Ubuntu" | ||||
| 					case strings.Contains(line, "debian"): | ||||
| 						platform = "Debian" | ||||
| 					default: | ||||
| 						platform = "Linux" | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	default: | ||||
| 		platform = "-" | ||||
| 	} | ||||
|  | ||||
| 	return platform | ||||
| } | ||||
|  | ||||
| func (start *Api) GetVersion() []string { | ||||
| 	return []string{Config.Get.Info.ProductName, Config.Get.Info.ProductVersion} | ||||
| } | ||||
| @@ -1,42 +0,0 @@ | ||||
| module cnc | ||||
|  | ||||
| go 1.18 | ||||
|  | ||||
| require ( | ||||
| 	github.com/gookit/color v1.5.2 | ||||
| 	github.com/wailsapp/wails/v2 v2.8.0 | ||||
| 	golang.org/x/sync v0.5.0 | ||||
| ) | ||||
|  | ||||
| require ( | ||||
| 	github.com/bep/debounce v1.2.1 // indirect | ||||
| 	github.com/go-ole/go-ole v1.2.6 // indirect | ||||
| 	github.com/godbus/dbus/v5 v5.1.0 // indirect | ||||
| 	github.com/google/uuid v1.3.0 // indirect | ||||
| 	github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect | ||||
| 	github.com/labstack/echo/v4 v4.10.2 // indirect | ||||
| 	github.com/labstack/gommon v0.4.0 // indirect | ||||
| 	github.com/leaanthony/go-ansi-parser v1.6.0 // indirect | ||||
| 	github.com/leaanthony/gosod v1.0.3 // indirect | ||||
| 	github.com/leaanthony/slicer v1.6.0 // indirect | ||||
| 	github.com/leaanthony/u v1.1.0 // indirect | ||||
| 	github.com/mattn/go-colorable v0.1.13 // indirect | ||||
| 	github.com/mattn/go-isatty v0.0.19 // indirect | ||||
| 	github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect | ||||
| 	github.com/pkg/errors v0.9.1 // indirect | ||||
| 	github.com/rivo/uniseg v0.4.4 // indirect | ||||
| 	github.com/samber/lo v1.38.1 // indirect | ||||
| 	github.com/tkrajina/go-reflector v0.5.6 // indirect | ||||
| 	github.com/valyala/bytebufferpool v1.0.0 // indirect | ||||
| 	github.com/valyala/fasttemplate v1.2.2 // indirect | ||||
| 	github.com/wailsapp/go-webview2 v1.0.10 // indirect | ||||
| 	github.com/wailsapp/mimetype v1.4.1 // indirect | ||||
| 	github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect | ||||
| 	golang.org/x/crypto v0.18.0 // indirect | ||||
| 	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect | ||||
| 	golang.org/x/net v0.20.0 // indirect | ||||
| 	golang.org/x/sys v0.16.0 // indirect | ||||
| 	golang.org/x/text v0.14.0 // indirect | ||||
| ) | ||||
|  | ||||
| // replace github.com/wailsapp/wails/v2 v2.3.1 => C:\Users\admin\go\pkg\mod | ||||
							
								
								
									
										103
									
								
								desktop/go.sum
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								desktop/go.sum
									
									
									
									
									
								
							| @@ -1,103 +0,0 @@ | ||||
| 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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| 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.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= | ||||
| github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= | ||||
| 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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | ||||
| github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI= | ||||
| github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= | ||||
| 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.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= | ||||
| github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= | ||||
| github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= | ||||
| github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= | ||||
| 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.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg= | ||||
| github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= | ||||
| github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= | ||||
| github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= | ||||
| github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= | ||||
| 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.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI= | ||||
| github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= | ||||
| github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= | ||||
| github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= | ||||
| github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= | ||||
| 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.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= | ||||
| github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= | ||||
| github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= | ||||
| github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | ||||
| github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= | ||||
| github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= | ||||
| 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.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= | ||||
| github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= | ||||
| github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= | ||||
| github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||||
| github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||||
| github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||||
| github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE= | ||||
| github.com/tkrajina/go-reflector v0.5.6/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.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | ||||
| 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.10 h1:PP5Hug6pnQEAhfRzLCoOh2jJaPdrqeRgJKZhyYyDV/w= | ||||
| github.com/wailsapp/go-webview2 v1.0.10/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= | ||||
| 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.8.0 h1:b2NNn99uGPiN6P5bDsnPwOJZWtAOUhNLv7Vl+YxMTr4= | ||||
| github.com/wailsapp/wails/v2 v2.8.0/go.mod h1:EFUGWkUX3KofO4fmKR/GmsLy3HhPH7NbyOEaMt8lBF0= | ||||
| github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= | ||||
| github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= | ||||
| golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= | ||||
| golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= | ||||
| golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= | ||||
| golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= | ||||
| golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||||
| golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= | ||||
| golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= | ||||
| golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= | ||||
| golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | ||||
| golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| 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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= | ||||
| golang.org/x/sys v0.16.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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= | ||||
| golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| @@ -1,26 +0,0 @@ | ||||
| /** | ||||
|  ****************************************************************************** | ||||
|  * @file    main.go | ||||
|  * @author  Makeryang | ||||
|  ****************************************************************************** | ||||
|  */ | ||||
|  | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"cnc/framework" | ||||
| 	"embed" | ||||
| 	"fmt" | ||||
| 	"github.com/gookit/color" | ||||
| ) | ||||
|  | ||||
| //go:embed all:template/dist | ||||
| var Template embed.FS | ||||
|  | ||||
| //go:embed all:wails.json | ||||
| var VersionInfo embed.FS | ||||
|  | ||||
| func main() { | ||||
| 	fmt.Println("[desktop][main]:" + color.Gray.Text("starting...")) | ||||
| 	Framework.Init(Template, VersionInfo) | ||||
| } | ||||
							
								
								
									
										175
									
								
								desktop/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								desktop/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | ||||
| { | ||||
|     "name": "mir2tools", | ||||
|     "title": "Mir2Tools", | ||||
|     "version": "1.0.0", | ||||
|     "author": "MakerYang", | ||||
|     "description": "mir2.makeryang.com", | ||||
|     "license": "MIT", | ||||
|     "type": "module", | ||||
|     "main": "release/dist/main/index.cjs", | ||||
|     "scripts": { | ||||
|         "dev": "node tools/script/watch.mjs", | ||||
|         "rebuild": "electron-rebuild -f -w", | ||||
|         "build": "rimraf release && node --max-old-space-size=6096 tools/script/build.mjs && node --max-old-space-size=6096 tools/script/index.mjs", | ||||
|         "win64": "electron-builder --win --x64", | ||||
|         "win32": "electron-builder --win --ia32", | ||||
|         "mac": "electron-builder --mac --x64", | ||||
|         "linux": "electron-builder --linux --amd64" | ||||
|     }, | ||||
|     "build": { | ||||
|         "productName": "Mir2Tools", | ||||
|         "appId": "com.makeryang.Mir2Tools", | ||||
|         "asar": true, | ||||
|         "buildDependenciesFromSource": true, | ||||
|         "directories": { | ||||
|             "output": "release/${version}" | ||||
|         }, | ||||
|         "fileAssociations": [], | ||||
|         "publish": [ | ||||
|             { | ||||
|                 "provider": "generic", | ||||
|                 "url": "" | ||||
|             } | ||||
|         ], | ||||
|         "files": [ | ||||
|             "release/dist" | ||||
|         ], | ||||
|         "dmg": { | ||||
|             "contents": [ | ||||
|                 { | ||||
|                     "x": 410, | ||||
|                     "y": 150, | ||||
|                     "type": "link", | ||||
|                     "path": "/Applications" | ||||
|                 }, | ||||
|                 { | ||||
|                     "x": 130, | ||||
|                     "y": 150, | ||||
|                     "type": "file" | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         "mac": { | ||||
|             "icon": "tools/icons/macos.icns", | ||||
|             "artifactName": "${productName}_${version}.${ext}" | ||||
|         }, | ||||
|         "win": { | ||||
|             "icon": "tools/icons/windows.ico", | ||||
|             "artifactName": "${productName}_${version}.${ext}", | ||||
|             "target": "nsis", | ||||
|             "requestedExecutionLevel": "highestAvailable" | ||||
|         }, | ||||
|         "linux": { | ||||
|             "icon": "tools/icons/icon.png", | ||||
|             "target": [ | ||||
|                 "AppImage" | ||||
|             ], | ||||
|             "artifactName": "${productName}_${version}.${ext}" | ||||
|         }, | ||||
|         "nsis": { | ||||
|             "oneClick": false, | ||||
|             "perMachine": true, | ||||
|             "allowElevation": true, | ||||
|             "allowToChangeInstallationDirectory": true, | ||||
|             "createDesktopShortcut": true, | ||||
|             "createStartMenuShortcut": true, | ||||
|             "installerIcon": "tools/icons/windows.ico", | ||||
|             "uninstallerIcon": "tools/icons/windows.ico", | ||||
|             "shortcutName": "Mir2Tools" | ||||
|         } | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@fingerprintjs/fingerprintjs": "^4.3.0", | ||||
|         "@formkit/auto-animate": "^0.8.2", | ||||
|         "@internationalized/date": "^3.5.4", | ||||
|         "@radix-icons/vue": "^1.0.0", | ||||
|         "@stackblitz/sdk": "^1.10.0", | ||||
|         "@tanstack/vue-table": "^8.17.3", | ||||
|         "@unovis/ts": "^1.4.1", | ||||
|         "@unovis/vue": "^1.4.1", | ||||
|         "@vee-validate/zod": "^4.12.8", | ||||
|         "@vue-flow/background": "^1.3.0", | ||||
|         "@vue-flow/controls": "^1.1.2", | ||||
|         "@vue-flow/core": "^1.38.2", | ||||
|         "@vue-flow/minimap": "^1.5.0", | ||||
|         "@vue-flow/node-toolbar": "^1.1.0", | ||||
|         "@vue/runtime-dom": "^3.4.27", | ||||
|         "@vueuse/core": "^10.9.0", | ||||
|         "axios": "^1.7.2", | ||||
|         "class-variance-authority": "^0.7.0", | ||||
|         "clsx": "^2.1.1", | ||||
|         "codesandbox": "^2.2.3", | ||||
|         "date-fns": "^3.6.0", | ||||
|         "electron-debug": "^3.2.0", | ||||
|         "electron-devtools-installer": "^3.2.0", | ||||
|         "electron-localstorage": "^1.0.5", | ||||
|         "electron-store": "^8.2.0", | ||||
|         "electron-updater": "^5.3.0", | ||||
|         "embla-carousel": "^8.1.3", | ||||
|         "embla-carousel-autoplay": "^8.1.3", | ||||
|         "embla-carousel-vue": "^8.1.3", | ||||
|         "lucide-vue-next": "^0.400.0", | ||||
|         "magic-string": "^0.30.10", | ||||
|         "postcss": "^8.4.38", | ||||
|         "radix-vue": "^1.8.1", | ||||
|         "tailwindcss-animate": "^1.0.7", | ||||
|         "terser": "^5.31.1", | ||||
|         "uuid": "^10.0.0", | ||||
|         "v-calendar": "^3.1.2", | ||||
|         "vaul-vue": "^0.1.2", | ||||
|         "vee-validate": "4.12.6", | ||||
|         "vue": "^3.4.27", | ||||
|         "vue-i18n": "^9.13.1", | ||||
|         "vue-router": "^4.1.5", | ||||
|         "vue-sonner": "^1.1.2", | ||||
|         "vue-wrap-balancer": "^1.1.3", | ||||
|         "zod": "^3.23.8" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "@babel/traverse": "^7.24.5", | ||||
|         "@iconify-json/gravity-ui": "^1.1.2", | ||||
|         "@iconify-json/lucide": "^1.1.187", | ||||
|         "@iconify-json/ph": "^1.1.13", | ||||
|         "@iconify-json/radix-icons": "^1.1.14", | ||||
|         "@iconify-json/ri": "^1.1.20", | ||||
|         "@iconify-json/simple-icons": "^1.1.102", | ||||
|         "@iconify-json/tabler": "^1.1.112", | ||||
|         "@iconify/vue": "^4.1.2", | ||||
|         "@oxc-parser/wasm": "^0.1.0", | ||||
|         "@shikijs/transformers": "^1.6.0", | ||||
|         "@types/lodash-es": "^4.17.12", | ||||
|         "@types/node": "^20.12.12", | ||||
|         "@vitejs/plugin-vue": "^5.0.4", | ||||
|         "@vitejs/plugin-vue-jsx": "^3.1.0", | ||||
|         "@vue/compiler-core": "^3.4.27", | ||||
|         "@vue/compiler-dom": "^3.4.27", | ||||
|         "@vue/tsconfig": "^0.5.1", | ||||
|         "autoprefixer": "^10.4.19", | ||||
|         "electron": "30.1.2", | ||||
|         "electron-builder": "24.13.3", | ||||
|         "electron-rebuild": "3.2.9", | ||||
|         "fast-glob": "^3.3.2", | ||||
|         "lodash-es": "^4.17.21", | ||||
|         "markdown-it": "^14.1.0", | ||||
|         "pathe": "^1.1.2", | ||||
|         "rimraf": "^5.0.7", | ||||
|         "sass": "^1.77.4", | ||||
|         "shiki": "^1.6.0", | ||||
|         "tailwind-merge": "^2.3.0", | ||||
|         "tailwindcss": "^3.4.3", | ||||
|         "tsx": "^4.10.5", | ||||
|         "typescript": "^5.4.5", | ||||
|         "unplugin-icons": "^0.19.0", | ||||
|         "vite": "^5.3.1", | ||||
|         "vite-plugin-electron": "^0.11.1", | ||||
|         "vite-plugin-top-level-await": "^1.3.0", | ||||
|         "vite-plugin-wasm": "^3.2.2", | ||||
|         "vitepress": "^1.2.3", | ||||
|         "vue-component-meta": "^2.0.19", | ||||
|         "vue-tsc": "^2.0.19" | ||||
|     }, | ||||
|     "env": { | ||||
|         "VITE_DEV_SERVER_HOST": "127.0.0.1", | ||||
|         "VITE_DEV_SERVER_PORT": 7676 | ||||
|     } | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 48 KiB | 
							
								
								
									
										87
									
								
								desktop/tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								desktop/tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| import defaultTheme from "tailwindcss/defaultTheme"; | ||||
| import tailwindcssAnimate from "tailwindcss-animate"; | ||||
|  | ||||
| export default { | ||||
|     darkMode: "class", | ||||
|     content: ["./template/src/**/*.{vue,js,ts,jsx,tsx,md}"], | ||||
|     theme: { | ||||
|         container: { | ||||
|             center: true, | ||||
|             padding: "0rem" | ||||
|         }, | ||||
|         extend: { | ||||
|             fontFamily: { | ||||
|                 sans: ['var(--font-geist-sans)', ...defaultTheme.fontFamily.sans], | ||||
|             }, | ||||
|             colors: { | ||||
|                 border: 'hsl(var(--border))', | ||||
|                 input: 'hsl(var(--input))', | ||||
|                 ring: 'hsl(var(--ring))', | ||||
|                 background: 'hsl(var(--background))', | ||||
|                 foreground: 'hsl(var(--foreground))', | ||||
|                 primary: { | ||||
|                     DEFAULT: 'hsl(var(--primary))', | ||||
|                     foreground: 'hsl(var(--primary-foreground))', | ||||
|                 }, | ||||
|                 secondary: { | ||||
|                     DEFAULT: 'hsl(var(--secondary))', | ||||
|                     foreground: 'hsl(var(--secondary-foreground))', | ||||
|                 }, | ||||
|                 destructive: { | ||||
|                     DEFAULT: 'hsl(var(--destructive))', | ||||
|                     foreground: 'hsl(var(--destructive-foreground))', | ||||
|                 }, | ||||
|                 muted: { | ||||
|                     DEFAULT: 'hsl(var(--muted))', | ||||
|                     foreground: 'hsl(var(--muted-foreground))', | ||||
|                 }, | ||||
|                 accent: { | ||||
|                     DEFAULT: 'hsl(var(--accent))', | ||||
|                     foreground: 'hsl(var(--accent-foreground))', | ||||
|                 }, | ||||
|                 popover: { | ||||
|                     DEFAULT: 'hsl(var(--popover))', | ||||
|                     foreground: 'hsl(var(--popover-foreground))', | ||||
|                 }, | ||||
|                 card: { | ||||
|                     DEFAULT: 'hsl(var(--card))', | ||||
|                     foreground: 'hsl(var(--card-foreground))', | ||||
|                 }, | ||||
|             }, | ||||
|             borderRadius: { | ||||
|                 xl: 'calc(var(--radius) + 4px)', | ||||
|                 lg: 'var(--radius)', | ||||
|                 md: 'calc(var(--radius) - 2px)', | ||||
|                 sm: 'calc(var(--radius) - 4px)', | ||||
|             }, | ||||
|             boxShadow: { | ||||
|                 switch: 'rgba(0, 0, 0, 0.3) 0px 0px 1px, rgba(0, 0, 0, 0.2) 0px 1px 2px', | ||||
|             }, | ||||
|             keyframes: { | ||||
|                 'accordion-down': { | ||||
|                     from: { height: 0 }, | ||||
|                     to: { height: 'var(--radix-accordion-content-height)' }, | ||||
|                 }, | ||||
|                 'accordion-up': { | ||||
|                     from: { height: 'var(--radix-accordion-content-height)' }, | ||||
|                     to: { height: 0 }, | ||||
|                 }, | ||||
|                 'collapsible-down': { | ||||
|                     from: { height: 0 }, | ||||
|                     to: { height: 'var(--radix-collapsible-content-height)' }, | ||||
|                 }, | ||||
|                 'collapsible-up': { | ||||
|                     from: { height: 'var(--radix-collapsible-content-height)' }, | ||||
|                     to: { height: 0 }, | ||||
|                 }, | ||||
|             }, | ||||
|             animation: { | ||||
|                 'accordion-down': 'accordion-down 0.2s ease-in-out', | ||||
|                 'accordion-up': 'accordion-up 0.2s ease-in-out', | ||||
|                 'collapsible-down': 'collapsible-down 0.2s ease-in-out', | ||||
|                 'collapsible-up': 'collapsible-up 0.2s ease-in-out', | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
|     plugins: [tailwindcssAnimate] | ||||
| } | ||||
| @@ -1,16 +0,0 @@ | ||||
| { | ||||
|     "$schema": "https://shadcn-vue.com/schema.json", | ||||
|     "style": "default", | ||||
|     "typescript": true, | ||||
|     "tailwind": { | ||||
|         "config": "tailwind.config.js", | ||||
|         "css": "src/assets/css/globals.css", | ||||
|         "baseColor": "slate", | ||||
|         "cssVariables": true | ||||
|     }, | ||||
|     "framework": "vite", | ||||
|     "aliases": { | ||||
|         "components": "@/component", | ||||
|         "utils": "@/package/lib/utils" | ||||
|     } | ||||
| } | ||||
| @@ -1,15 +1,12 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|  | ||||
| <head> | ||||
|     <meta charset="UTF-8" /> | ||||
|     <meta content="width=device-width, initial-scale=1.0" name="viewport" /> | ||||
|     <title>Index</title> | ||||
|     <title></title> | ||||
| </head> | ||||
|  | ||||
| <body> | ||||
|     <div id="app"></div> | ||||
|     <script src="./src/main.ts" type="module"></script> | ||||
| <div id="app"></div> | ||||
| <script src="./src/main.ts" type="module"></script> | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
| @@ -1,45 +0,0 @@ | ||||
| { | ||||
|     "name": "frontend", | ||||
|     "private": true, | ||||
|     "version": "0.0.0", | ||||
|     "scripts": { | ||||
|         "dev": "vite", | ||||
|         "rebuild": "node-gyp rebuild", | ||||
|         "build": "vue-tsc --noEmit && vite build", | ||||
|         "preview": "vite preview" | ||||
|     }, | ||||
|     "engines": { | ||||
|         "node": ">=18" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@element-plus/icons": "^0.0.11", | ||||
|         "@element-plus/icons-vue": "^2.0.9", | ||||
|         "@radix-ui/react-slot": "^1.0.2", | ||||
|         "axios": "^0.27.2", | ||||
|         "class-variance-authority": "^0.7.0", | ||||
|         "clsx": "^2.1.0", | ||||
|         "element-plus": "2.3.7", | ||||
|         "lucide-react": "^0.365.0", | ||||
|         "lucide-vue-next": "^0.365.0", | ||||
|         "radix-vue": "^1.6.2", | ||||
|         "tailwind-merge": "^2.2.2", | ||||
|         "tailwindcss-animate": "^1.0.7", | ||||
|         "uuid": "^9.0.0", | ||||
|         "vue": "3.2.37", | ||||
|         "vue-router": "4.1.5" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "@babel/types": "^7.18.10", | ||||
|         "@types/node": "^18.11.18", | ||||
|         "@types/react": "^18.2.56", | ||||
|         "@vitejs/plugin-react": "^4.2.1", | ||||
|         "@vitejs/plugin-vue": "^3.0.3", | ||||
|         "@vue/tsconfig": "0.1.3", | ||||
|         "autoprefixer": "^10.4.19", | ||||
|         "tailwindcss": "^3.4.3", | ||||
|         "postcss": "latest", | ||||
|         "typescript": "4.6.4", | ||||
|         "vite": "3.0.7", | ||||
|         "vue-tsc": "0.39.5" | ||||
|     } | ||||
| } | ||||
| @@ -1 +0,0 @@ | ||||
| b675ea4ecb792710e5c6c1ecae1ddf7b | ||||
| @@ -1,6 +0,0 @@ | ||||
| module.exports = { | ||||
|     plugins: { | ||||
|         tailwindcss: {}, | ||||
|         autoprefixer: {}, | ||||
|     } | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 15 KiB | 
							
								
								
									
										
											BIN
										
									
								
								desktop/template/public/image/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								desktop/template/public/image/icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 7.2 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 20 KiB | 
| @@ -1,37 +1,104 @@ | ||||
| <template> | ||||
|     <router-view ref="routerView" v-slot="{Component}"> | ||||
|         <component :is="Component" :cnc="appData" /> | ||||
|         <component :is="Component" :data="data" :base="base" /> | ||||
|     </router-view> | ||||
|     <Toaster ref="toaster" /> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import {ref, defineComponent} from "vue"; | ||||
| import {ElLoading} from "element-plus"; | ||||
| export default defineComponent({ | ||||
|     name: "App", | ||||
|     emits: [], | ||||
|     props: [], | ||||
|     components: {}, | ||||
|     setup(props, context) { | ||||
| <script setup lang="ts"> | ||||
| import {onBeforeMount, onMounted, onBeforeUnmount, onUnmounted, nextTick, ref} from "vue"; | ||||
| import {useRoute, useRouter, useI18n, useDark, useStore, Request, ThemeColors} from "./packages"; | ||||
| import {useForm, toTypedSchema, object, string} from "./packages"; | ||||
| import {Toaster, useToast} from "@/lib/toast"; | ||||
|  | ||||
|         const appData: any = ref({ | ||||
|             loading: ElLoading.service({ | ||||
|                 lock: true, | ||||
|                 background: "rgba(0, 0, 0, .5)", | ||||
|                 customClass: "desktop", | ||||
|             }), | ||||
|             data: false | ||||
|         }); | ||||
| const $route = useRoute(); | ||||
| const $router = useRouter(); | ||||
| const $store = useStore(); | ||||
| const {toast} = useToast(); | ||||
|  | ||||
|         return { | ||||
|             props, | ||||
|             appData | ||||
| const i18n = useI18n(); | ||||
| const base: any = (window as any).base; | ||||
| const data: any = ref({ | ||||
|     base: (window as any).base, | ||||
|     route: $route, | ||||
|     router: $router, | ||||
|     store: $store, | ||||
|     theme: { | ||||
|         colors: ThemeColors, | ||||
|         dark: useDark() | ||||
|     }, | ||||
|     header: { | ||||
|         search: { | ||||
|             status: false | ||||
|         } | ||||
|     }, | ||||
|     page: { | ||||
|         current: "", | ||||
|         login: { | ||||
|             type: "login", | ||||
|             code: { | ||||
|                 timer: null, | ||||
|                 count: 60, | ||||
|                 loading: false | ||||
|             }, | ||||
|             loading: false | ||||
|         } | ||||
|     }, | ||||
|     service: { | ||||
|         loading: false, | ||||
|         account: { | ||||
|             token: "" | ||||
|         }, | ||||
|     }, | ||||
|     browser: { | ||||
|         language: (navigator as any).language, | ||||
|         toast: toast, | ||||
|         request: Request, | ||||
|         form: { | ||||
|             use: useForm, | ||||
|             schema: toTypedSchema, | ||||
|             object: object, | ||||
|             string: string | ||||
|         }, | ||||
|         network: { | ||||
|             status: false | ||||
|         } | ||||
|     } | ||||
| }); | ||||
|  | ||||
| onBeforeMount(() => {}); | ||||
|  | ||||
| onMounted(() => { | ||||
|     data.value.base.process = process; | ||||
|     console.log("Mir2Tools " + data.value.browser.language + " " + data.value.base.environment(process) + " " + data.value.base.config.version + " " + data.value.base.config.author); | ||||
|     console.log("Platform:" + data.value.base.platform + " Electron:" + data.value.base.process.versions.electron + " Chromium:" + data.value.base.process.versions.chrome + " NodeJS:" + data.value.base.process.versions.node); | ||||
|     console.log("Path:" + data.value.base.app_path(process) + " Data:" + data.value.base.app_data_path(process) + " Home:" + data.value.base.app_home_path(process) + " Temp:" + data.value.base.app_temp_path(process)); | ||||
|     document.documentElement.style.setProperty("--radius", `${$store.radius.value}rem`); | ||||
|     document.documentElement.classList.add(`theme-${$store.theme.value}`); | ||||
|     nextTick(() => { | ||||
|         data.value.base.lang.t = i18n.t; | ||||
|         data.value.base.lang.locale = i18n.locale; | ||||
|         if(data.value.base.lang.locale === "null"){ | ||||
|             if(data.value.browser.language === "zh-CN"){ | ||||
|                 data.value.base.lang.locale = "zh"; | ||||
|             }else{ | ||||
|                 data.value.base.lang.locale = "en"; | ||||
|             } | ||||
|         } | ||||
|         window.addEventListener("resize", function() { | ||||
|             data.value.base.ipc.send("message", {type: "header:right:button", data: "resize"}); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| onBeforeUnmount(() => {}); | ||||
|  | ||||
| onUnmounted(() => {}); | ||||
| </script> | ||||
|  | ||||
| <style> | ||||
| @import "./assets/css/base.css"; | ||||
| @import "./assets/css/globals.css"; | ||||
| @import url("./assets/css/shiki.css"); | ||||
| @import url("./assets/css/tailwind.css"); | ||||
| @import url("./assets/css/themes.css"); | ||||
| @import url("./assets/css/markdown.css"); | ||||
| </style> | ||||
|   | ||||
| @@ -1,76 +0,0 @@ | ||||
| @charset "UTF-8"; | ||||
|  | ||||
| @tailwind base; | ||||
| @tailwind components; | ||||
| @tailwind utilities; | ||||
|  | ||||
| @layer base { | ||||
|     :root { | ||||
|         --background: 0 0% 100%; | ||||
|         --foreground: 240 10% 3.9%; | ||||
|  | ||||
|         --card: 0 0% 100%; | ||||
|         --card-foreground: 240 10% 3.9%; | ||||
|  | ||||
|         --popover: 0 0% 100%; | ||||
|         --popover-foreground: 240 10% 3.9%; | ||||
|  | ||||
|         --primary: 240 5.9% 10%; | ||||
|         --primary-foreground: 0 0% 98%; | ||||
|  | ||||
|         --secondary: 240 4.8% 95.9%; | ||||
|         --secondary-foreground: 240 5.9% 10%; | ||||
|         --muted: 240 4.8% 95.9%; | ||||
|         --muted-foreground: 240 3.8% 46.1%; | ||||
|         --accent: 240 4.8% 95.9%; | ||||
|         --accent-foreground: 240 5.9% 10%; | ||||
|  | ||||
|         --destructive: 0 84.2% 60.2%; | ||||
|         --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|         --border:240 5.9% 90%; | ||||
|         --input:240 5.9% 90%; | ||||
|         --ring:240 5.9% 10%; | ||||
|         --radius: 0.5rem; | ||||
|     } | ||||
|  | ||||
|     .dark { | ||||
|         --background:240 10% 3.9%; | ||||
|         --foreground:0 0% 98%; | ||||
|  | ||||
|         --card:240 10% 3.9%; | ||||
|         --card-foreground:0 0% 98%; | ||||
|  | ||||
|         --popover:240 10% 3.9%; | ||||
|         --popover-foreground:0 0% 98%; | ||||
|  | ||||
|         --primary:0 0% 98%; | ||||
|         --primary-foreground:240 5.9% 10%; | ||||
|  | ||||
|         --secondary:240 3.7% 15.9%; | ||||
|         --secondary-foreground:0 0% 98%; | ||||
|  | ||||
|         --muted:240 3.7% 15.9%; | ||||
|         --muted-foreground:240 5% 64.9%; | ||||
|  | ||||
|         --accent:240 3.7% 15.9%; | ||||
|         --accent-foreground:0 0% 98%; | ||||
|  | ||||
|         --destructive:0 62.8% 30.6%; | ||||
|         --destructive-foreground:0 0% 98%; | ||||
|  | ||||
|         --border:240 3.7% 15.9%; | ||||
|         --input:240 3.7% 15.9%; | ||||
|         --ring:240 4.9% 83.9%; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| @layer base { | ||||
|     * { | ||||
|         @apply border-border; | ||||
|     } | ||||
|     body { | ||||
|         @apply bg-background text-foreground; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								desktop/template/src/assets/css/markdown.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								desktop/template/src/assets/css/markdown.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| :root { | ||||
|     --vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); | ||||
|     --vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); | ||||
|     --vp-code-bg: hsl(var(--muted)); | ||||
|     --vp-c-divider: hsl(var(--muted)); | ||||
|     --vp-code-block-color: #fff | ||||
| } | ||||
|  | ||||
| .vp-doc { | ||||
|  | ||||
| } | ||||
							
								
								
									
										52
									
								
								desktop/template/src/assets/css/shiki.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								desktop/template/src/assets/css/shiki.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| :root { | ||||
|     --shiki-foreground: #FFF8; | ||||
|     --shiki-color-background: #ffffff; | ||||
|     --shiki-token-constant: #ffffff; | ||||
|     --shiki-token-string: #ffffff88; | ||||
|     --shiki-token-comment: #ffffff88; | ||||
|     --shiki-token-keyword: #ffffff88; | ||||
|     --shiki-token-parameter: #AA0000; | ||||
|     --shiki-token-function: #ffffff; | ||||
|     --shiki-token-string-expression: #ebebeb; | ||||
|     --shiki-token-punctuation: #ffffff; | ||||
|     --shiki-token-link: #EE0000; | ||||
| } | ||||
|  | ||||
| .shiki .highlighted-word { | ||||
|     border-radius: calc(var(--radius) - 2px); | ||||
|     border-color: rgba(63,63,70,.7); | ||||
|     background-color: rgba(63,63,70,.5); | ||||
|     padding: 0.25rem; | ||||
| } | ||||
|  | ||||
| .alert-default{ | ||||
|     background-color: #f4f4f5; | ||||
|     color: #909399; | ||||
| } | ||||
| .dark .alert-default{ | ||||
|     background-color: #202121; | ||||
|     color: #909399; | ||||
| } | ||||
| .alert-warning{ | ||||
|     background-color: #fdf6ec; | ||||
|     color: #e6a23c; | ||||
| } | ||||
| .dark .alert-warning{ | ||||
|     background-color: #292218; | ||||
|     color: #e6a23c; | ||||
| } | ||||
| .alert-error{ | ||||
|     background-color: #fef0f0; | ||||
|     color: #f56c6c; | ||||
| } | ||||
| .dark .alert-error{ | ||||
|     background-color: #2b1d1d; | ||||
|     color: #f56c6c; | ||||
| } | ||||
|  | ||||
| .drag{ | ||||
|     -webkit-app-region: drag; | ||||
| } | ||||
| .no-drag{ | ||||
|     -webkit-app-region: no-drag; | ||||
| } | ||||
							
								
								
									
										188
									
								
								desktop/template/src/assets/css/tailwind.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								desktop/template/src/assets/css/tailwind.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,188 @@ | ||||
| @tailwind base; | ||||
| @tailwind components; | ||||
| @tailwind utilities; | ||||
|  | ||||
| @layer base { | ||||
|   :root { | ||||
|     --font-geist-sans: "geist-sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, | ||||
|     Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; | ||||
|  | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 240 10% 3.9%; | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 240 10% 3.9%; | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 240 10% 3.9%; | ||||
|     --primary: 240 5.9% 10%; | ||||
|     --primary-foreground: 0 0% 98%; | ||||
|     --secondary: 240 4.8% 95.9%; | ||||
|     --secondary-foreground: 240 5.9% 10%; | ||||
|     --muted: 240 4.8% 95.9%; | ||||
|     --muted-foreground: 240 3.8% 46.1%; | ||||
|     --accent: 240 4.8% 95.9%; | ||||
|     --accent-foreground: 240 5.9% 10%; | ||||
|     --destructive: 0 72.22% 50.59%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|     --border: 240 5.9% 90%; | ||||
|     --input: 240 5.9% 90%; | ||||
|     --ring: 240 5% 64.9%; | ||||
|     --radius: 0.5rem; | ||||
|  | ||||
|     --vis-primary-color: var(--primary); | ||||
|     --vis-secondary-color: 160 81% 40%; | ||||
|     --vis-text-color: var(--muted-foreground); | ||||
|  | ||||
|     --vis-font-family: inherit !important; | ||||
|     --vis-area-stroke-width: 2px !important; | ||||
|     --vis-donut-central-label-text-color: hsl(var(--muted-foreground)) !important; | ||||
|     --vis-tooltip-background-color: none !important; | ||||
|     --vis-tooltip-border-color: none !important; | ||||
|     --vis-tooltip-text-color: none !important; | ||||
|     --vis-tooltip-shadow-color: none !important; | ||||
|     --vis-tooltip-backdrop-filter: none !important; | ||||
|     --vis-tooltip-padding: none !important; | ||||
|   } | ||||
|  | ||||
|   .dark { | ||||
|     --background: 240 10% 3.9%; | ||||
|     --foreground: 0 0% 98%; | ||||
|     --card: 240 10% 3.9%; | ||||
|     --card-foreground: 0 0% 98%; | ||||
|     --popover: 240 10% 3.9%; | ||||
|     --popover-foreground: 0 0% 98%; | ||||
|     --primary: 0 0% 98%; | ||||
|     --primary-foreground: 240 5.9% 10%; | ||||
|     --secondary: 240 3.7% 15.9%; | ||||
|     --secondary-foreground: 0 0% 98%; | ||||
|     --muted: 240 3.7% 15.9%; | ||||
|     --muted-foreground: 240 5% 64.9%; | ||||
|     --accent: 240 3.7% 15.9%; | ||||
|     --accent-foreground: 0 0% 98%; | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 0 85.7% 97.3%; | ||||
|     --border: 240 3.7% 15.9%; | ||||
|     --input: 240 3.7% 15.9%; | ||||
|     --ring: 240 4.9% 83.9%; | ||||
|   } | ||||
|  | ||||
|   * { | ||||
|     @apply border-border; | ||||
|   } | ||||
|   html { | ||||
|     -webkit-text-size-adjust: 100%; | ||||
|     font-variation-settings: normal; | ||||
|   } | ||||
|   body { | ||||
|     @apply bg-background text-foreground min-h-screen antialiased font-sans; | ||||
|     /* font-feature-settings: "rlig" 1, "calt" 1; */ | ||||
|     font-synthesis-weight: none; | ||||
|     text-rendering: optimizeLegibility; | ||||
|   } | ||||
|  | ||||
|   /* Mobile tap highlight */ | ||||
|   /* https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-tap-highlight-color */ | ||||
|   html { | ||||
|     -webkit-tap-highlight-color: rgba(128, 128, 128, 0.5); | ||||
|   } | ||||
|  | ||||
|   /* Font face Geist font */ | ||||
|  | ||||
|   @font-face { | ||||
|     font-family: "geist-sans"; | ||||
|     font-style: normal; | ||||
|     font-weight: 100 900; | ||||
|     font-display: swap; | ||||
|     src: url("../fonts/Geist/GeistVariableVF.woff2") format("woff2"); | ||||
|   } | ||||
|  | ||||
|   /* === Scrollbars === */ | ||||
|  | ||||
|   ::-webkit-scrollbar { | ||||
|     @apply w-2; | ||||
|     @apply h-2; | ||||
|   } | ||||
|  | ||||
|   ::-webkit-scrollbar-track { | ||||
|     @apply !bg-muted; | ||||
|   } | ||||
|   ::-webkit-scrollbar-thumb { | ||||
|     @apply rounded-sm !bg-muted-foreground/30; | ||||
|   } | ||||
|  | ||||
|   /* Firefox */ | ||||
|   /* https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color#browser_compatibility */ | ||||
|   html { | ||||
|     scrollbar-color: hsl(215.4 16.3% 46.9% / 0.3); | ||||
|   } | ||||
|  | ||||
|   html.dark { | ||||
|     scrollbar-color: hsl(215.4 16.3% 56.9% / 0.3); | ||||
|   } | ||||
|  | ||||
|   .hide-scrollbar::-webkit-scrollbar { | ||||
|     display: none; | ||||
|   } | ||||
|  | ||||
|   .hide-scrollbar { | ||||
|     -ms-overflow-style: none; | ||||
|     scrollbar-width: none; | ||||
|   } | ||||
|  | ||||
|   .antialised { | ||||
|     -webkit-font-smoothing: antialiased; | ||||
|     -moz-osx-font-smoothing: grayscale; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @layer utilities { | ||||
|   .step { | ||||
|     counter-increment: step; | ||||
|   } | ||||
|  | ||||
|   .step:before { | ||||
|     @apply absolute w-9 h-9 bg-muted rounded-full font-mono font-medium text-center text-base inline-flex items-center justify-center -indent-px border-4 border-background; | ||||
|     @apply -ml-[50px] -mt-1; | ||||
|     content: counter(step); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media (max-width: 640px) { | ||||
|   .container { | ||||
|     @apply px-4; | ||||
|   } | ||||
| } | ||||
|  | ||||
| div[class^="language-"] { | ||||
|   @apply mb-4 mt-6 max-h-[650px] overflow-x-auto md:rounded-lg border !bg-secondary-foreground dark:!bg-secondary | ||||
| } | ||||
|  | ||||
| pre { | ||||
|   @apply py-4; | ||||
| } | ||||
|  | ||||
| pre code { | ||||
|   @apply relative font-mono text-sm ; | ||||
| } | ||||
|  | ||||
| .line-numbers-wrapper, code { | ||||
|   --vp-code-line-height: 1.7; | ||||
| } | ||||
|  | ||||
| .line-numbers-wrapper { | ||||
|   @apply font-mono; | ||||
| } | ||||
|  | ||||
| pre code .line { | ||||
|   @apply px-4 min-h-4 !py-0.5 w-full inline-block leading-[--vp-code-line-height]; | ||||
| } | ||||
|  | ||||
| .line-number { | ||||
|   @apply !text-[.75rem] !inline-block text-muted-foreground leading-[--vp-code-line-height]; | ||||
| } | ||||
|  | ||||
| ::view-transition-old(root), | ||||
| ::view-transition-new(root) { | ||||
|   animation-duration: 0.3s; | ||||
| } | ||||
|  | ||||
							
								
								
									
										793
									
								
								desktop/template/src/assets/css/themes.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										793
									
								
								desktop/template/src/assets/css/themes.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,793 @@ | ||||
| html { | ||||
|     color-scheme: light; | ||||
|     --el-empty-fill-color-1: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-2: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-3: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-4: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-5: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-6: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-7: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-8: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-9: hsl(var(--muted)); | ||||
| } | ||||
|  | ||||
| html.dark { | ||||
|     color-scheme: dark; | ||||
|     --el-empty-fill-color-1: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-2: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-3: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-4: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-5: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-6: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-7: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-8: hsl(var(--muted)); | ||||
|     --el-empty-fill-color-9: hsl(var(--muted)); | ||||
| } | ||||
|  | ||||
| .theme-zinc { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --muted: 240 4.8% 95.9%; | ||||
|     --muted-foreground: 240 3.8% 46.1%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --border: 240 5.9% 90%; | ||||
|     --input: 240 5.9% 90%; | ||||
|  | ||||
|     --primary: 240 5.9% 10%; | ||||
|     --primary-foreground: 0 0% 98%; | ||||
|  | ||||
|     --secondary: 240 4.8% 95.9%; | ||||
|     --secondary-foreground: 240 5.9% 10%; | ||||
|  | ||||
|     --accent: 240 4.8% 95.9%; | ||||
|     --accent-foreground: 240 5.9% 10%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|     --ring: 240 5.9% 10%; | ||||
|  | ||||
|     --radius: 0.5rem; | ||||
| } | ||||
|  | ||||
| .theme-zinc.dark { | ||||
|     --background: 240 10% 3.9%; | ||||
|     --foreground: 0 0% 98%; | ||||
|  | ||||
|     --muted: 240 3.7% 15.9%; | ||||
|     --muted-foreground: 240 5% 64.9%; | ||||
|  | ||||
|     --popover: 240 10% 3.9%; | ||||
|     --popover-foreground: 0 0% 98%; | ||||
|  | ||||
|     --card: 240 10% 3.9%; | ||||
|     --card-foreground: 0 0% 98%; | ||||
|  | ||||
|     --border: 240 3.7% 15.9%; | ||||
|     --input: 240 3.7% 15.9%; | ||||
|  | ||||
|     --primary: 0 0% 98%; | ||||
|     --primary-foreground: 240 5.9% 10%; | ||||
|  | ||||
|     --secondary: 240 3.7% 15.9%; | ||||
|     --secondary-foreground: 0 0% 98%; | ||||
|  | ||||
|     --accent: 240 3.7% 15.9%; | ||||
|     --accent-foreground: 0 0% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|     --ring: 240 4.9% 83.9%; | ||||
| } | ||||
|  | ||||
| .theme-slate { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 222.2 84% 4.9%; | ||||
|  | ||||
|     --muted: 210 40% 96.1%; | ||||
|     --muted-foreground: 215.4 16.3% 46.9%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 222.2 84% 4.9%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 222.2 84% 4.9%; | ||||
|  | ||||
|     --border: 214.3 31.8% 91.4%; | ||||
|     --input: 214.3 31.8% 91.4%; | ||||
|  | ||||
|     --primary: 222.2 47.4% 11.2%; | ||||
|     --primary-foreground: 210 40% 98%; | ||||
|  | ||||
|     --secondary: 210 40% 96.1%; | ||||
|     --secondary-foreground: 222.2 47.4% 11.2%; | ||||
|  | ||||
|     --accent: 210 40% 96.1%; | ||||
|     --accent-foreground: 222.2 47.4% 11.2%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 210 40% 98%; | ||||
|  | ||||
|     --ring: 222.2 84% 4.9%; | ||||
|  | ||||
|     --radius: 0.5rem; | ||||
| } | ||||
|  | ||||
| .theme-slate.dark { | ||||
|     --background: 222.2 84% 4.9%; | ||||
|     --foreground: 210 40% 98%; | ||||
|  | ||||
|     --muted: 217.2 32.6% 17.5%; | ||||
|     --muted-foreground: 215 20.2% 65.1%; | ||||
|  | ||||
|     --popover: 222.2 84% 4.9%; | ||||
|     --popover-foreground: 210 40% 98%; | ||||
|  | ||||
|     --card: 222.2 84% 4.9%; | ||||
|     --card-foreground: 210 40% 98%; | ||||
|  | ||||
|     --border: 217.2 32.6% 17.5%; | ||||
|     --input: 217.2 32.6% 17.5%; | ||||
|  | ||||
|     --primary: 210 40% 98%; | ||||
|     --primary-foreground: 222.2 47.4% 11.2%; | ||||
|  | ||||
|     --secondary: 217.2 32.6% 17.5%; | ||||
|     --secondary-foreground: 210 40% 98%; | ||||
|  | ||||
|     --accent: 217.2 32.6% 17.5%; | ||||
|     --accent-foreground: 210 40% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 210 40% 98%; | ||||
|  | ||||
|     --ring: 212.7 26.8% 83.9; | ||||
| } | ||||
|  | ||||
| .theme-stone { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --muted: 60 4.8% 95.9%; | ||||
|     --muted-foreground: 25 5.3% 44.7%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --border: 20 5.9% 90%; | ||||
|     --input: 20 5.9% 90%; | ||||
|  | ||||
|     --primary: 24 9.8% 10%; | ||||
|     --primary-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --secondary: 60 4.8% 95.9%; | ||||
|     --secondary-foreground: 24 9.8% 10%; | ||||
|  | ||||
|     --accent: 60 4.8% 95.9%; | ||||
|     --accent-foreground: 24 9.8% 10%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --ring: 20 14.3% 4.1%; | ||||
|  | ||||
|     --radius: 0.95rem; | ||||
| } | ||||
|  | ||||
| .theme-stone.dark { | ||||
|     --background: 20 14.3% 4.1%; | ||||
|     --foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --muted: 12 6.5% 15.1%; | ||||
|     --muted-foreground: 24 5.4% 63.9%; | ||||
|  | ||||
|     --popover: 20 14.3% 4.1%; | ||||
|     --popover-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --card: 20 14.3% 4.1%; | ||||
|     --card-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --border: 12 6.5% 15.1%; | ||||
|     --input: 12 6.5% 15.1%; | ||||
|  | ||||
|     --primary: 60 9.1% 97.8%; | ||||
|     --primary-foreground: 24 9.8% 10%; | ||||
|  | ||||
|     --secondary: 12 6.5% 15.1%; | ||||
|     --secondary-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --accent: 12 6.5% 15.1%; | ||||
|     --accent-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --ring: 24 5.7% 82.9%; | ||||
| } | ||||
|  | ||||
| .theme-gray { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 224 71.4% 4.1%; | ||||
|  | ||||
|     --muted: 220 14.3% 95.9%; | ||||
|     --muted-foreground: 220 8.9% 46.1%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 224 71.4% 4.1%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 224 71.4% 4.1%; | ||||
|  | ||||
|     --border: 220 13% 91%; | ||||
|     --input: 220 13% 91%; | ||||
|  | ||||
|     --primary: 220.9 39.3% 11%; | ||||
|     --primary-foreground: 210 20% 98%; | ||||
|  | ||||
|     --secondary: 220 14.3% 95.9%; | ||||
|     --secondary-foreground: 220.9 39.3% 11%; | ||||
|  | ||||
|     --accent: 220 14.3% 95.9%; | ||||
|     --accent-foreground: 220.9 39.3% 11%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 210 20% 98%; | ||||
|  | ||||
|     --ring: 224 71.4% 4.1%; | ||||
|  | ||||
|     --radius: 0.35rem; | ||||
| } | ||||
|  | ||||
| .theme-gray.dark { | ||||
|     --background: 224 71.4% 4.1%; | ||||
|     --foreground: 210 20% 98%; | ||||
|  | ||||
|     --muted: 215 27.9% 16.9%; | ||||
|     --muted-foreground: 217.9 10.6% 64.9%; | ||||
|  | ||||
|     --popover: 224 71.4% 4.1%; | ||||
|     --popover-foreground: 210 20% 98%; | ||||
|  | ||||
|     --card: 224 71.4% 4.1%; | ||||
|     --card-foreground: 210 20% 98%; | ||||
|  | ||||
|     --border: 215 27.9% 16.9%; | ||||
|     --input: 215 27.9% 16.9%; | ||||
|  | ||||
|     --primary: 210 20% 98%; | ||||
|     --primary-foreground: 220.9 39.3% 11%; | ||||
|  | ||||
|     --secondary: 215 27.9% 16.9%; | ||||
|     --secondary-foreground: 210 20% 98%; | ||||
|  | ||||
|     --accent: 215 27.9% 16.9%; | ||||
|     --accent-foreground: 210 20% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 210 20% 98%; | ||||
|  | ||||
|     --ring: 216 12.2% 83.9%; | ||||
| } | ||||
|  | ||||
| .theme-neutral { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 0 0% 3.9%; | ||||
|  | ||||
|     --muted: 0 0% 96.1%; | ||||
|     --muted-foreground: 0 0% 45.1%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 0 0% 3.9%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 0 0% 3.9%; | ||||
|  | ||||
|     --border: 0 0% 89.8%; | ||||
|     --input: 0 0% 89.8%; | ||||
|  | ||||
|     --primary: 0 0% 9%; | ||||
|     --primary-foreground: 0 0% 98%; | ||||
|  | ||||
|     --secondary: 0 0% 96.1%; | ||||
|     --secondary-foreground: 0 0% 9%; | ||||
|  | ||||
|     --accent: 0 0% 96.1%; | ||||
|     --accent-foreground: 0 0% 9%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|     --ring: 0 0% 3.9%; | ||||
|  | ||||
|     --radius: ; | ||||
| } | ||||
|  | ||||
| .theme-neutral.dark { | ||||
|     --background: 0 0% 3.9%; | ||||
|     --foreground: 0 0% 98%; | ||||
|  | ||||
|     --muted: 0 0% 14.9%; | ||||
|     --muted-foreground: 0 0% 63.9%; | ||||
|  | ||||
|     --popover: 0 0% 3.9%; | ||||
|     --popover-foreground: 0 0% 98%; | ||||
|  | ||||
|     --card: 0 0% 3.9%; | ||||
|     --card-foreground: 0 0% 98%; | ||||
|  | ||||
|     --border: 0 0% 14.9%; | ||||
|     --input: 0 0% 14.9%; | ||||
|  | ||||
|     --primary: 0 0% 98%; | ||||
|     --primary-foreground: 0 0% 9%; | ||||
|  | ||||
|     --secondary: 0 0% 14.9%; | ||||
|     --secondary-foreground: 0 0% 98%; | ||||
|  | ||||
|     --accent: 0 0% 14.9%; | ||||
|     --accent-foreground: 0 0% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|     --ring: 0 0% 83.1%; | ||||
| } | ||||
|  | ||||
| .theme-red { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 0 0% 3.9%; | ||||
|  | ||||
|     --muted: 0 0% 96.1%; | ||||
|     --muted-foreground: 0 0% 45.1%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 0 0% 3.9%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 0 0% 3.9%; | ||||
|  | ||||
|     --border: 0 0% 89.8%; | ||||
|     --input: 0 0% 89.8%; | ||||
|  | ||||
|     --primary: 0 72.2% 50.6%; | ||||
|     --primary-foreground: 0 85.7% 97.3%; | ||||
|  | ||||
|     --secondary: 0 0% 96.1%; | ||||
|     --secondary-foreground: 0 0% 9%; | ||||
|  | ||||
|     --accent: 0 0% 96.1%; | ||||
|     --accent-foreground: 0 0% 9%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|     --ring: 0 72.2% 50.6%; | ||||
|  | ||||
|     --radius: 0.4rem; | ||||
| } | ||||
|  | ||||
| .theme-red.dark { | ||||
|     --background: 0 0% 3.9%; | ||||
|     --foreground: 0 0% 98%; | ||||
|  | ||||
|     --muted: 0 0% 14.9%; | ||||
|     --muted-foreground: 0 0% 63.9%; | ||||
|  | ||||
|     --popover: 0 0% 3.9%; | ||||
|     --popover-foreground: 0 0% 98%; | ||||
|  | ||||
|     --card: 0 0% 3.9%; | ||||
|     --card-foreground: 0 0% 98%; | ||||
|  | ||||
|     --border: 0 0% 14.9%; | ||||
|     --input: 0 0% 14.9%; | ||||
|  | ||||
|     --primary: 0 72.2% 50.6%; | ||||
|     --primary-foreground: 0 85.7% 97.3%; | ||||
|  | ||||
|     --secondary: 0 0% 14.9%; | ||||
|     --secondary-foreground: 0 0% 98%; | ||||
|  | ||||
|     --accent: 0 0% 14.9%; | ||||
|     --accent-foreground: 0 0% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|     --ring: 0 72.2% 50.6%; | ||||
| } | ||||
|  | ||||
| .theme-rose { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --muted: 240 4.8% 95.9%; | ||||
|     --muted-foreground: 240 3.8% 46.1%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --border: 240 5.9% 90%; | ||||
|     --input: 240 5.9% 90%; | ||||
|  | ||||
|     --primary: 346.8 77.2% 49.8%; | ||||
|     --primary-foreground: 355.7 100% 97.3%; | ||||
|  | ||||
|     --secondary: 240 4.8% 95.9%; | ||||
|     --secondary-foreground: 240 5.9% 10%; | ||||
|  | ||||
|     --accent: 240 4.8% 95.9%; | ||||
|     --accent-foreground: 240 5.9% 10%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|     --ring: 346.8 77.2% 49.8%; | ||||
|  | ||||
|     --radius: 0.5rem; | ||||
| } | ||||
|  | ||||
| .theme-rose.dark { | ||||
|     --background: 20 14.3% 4.1%; | ||||
|     --foreground: 0 0% 95%; | ||||
|  | ||||
|     --muted: 0 0% 15%; | ||||
|     --muted-foreground: 240 5% 64.9%; | ||||
|  | ||||
|     --popover: 0 0% 9%; | ||||
|     --popover-foreground: 0 0% 95%; | ||||
|  | ||||
|     --card: 24 9.8% 10%; | ||||
|     --card-foreground: 0 0% 95%; | ||||
|  | ||||
|     --border: 240 3.7% 15.9%; | ||||
|     --input: 240 3.7% 15.9%; | ||||
|  | ||||
|     --primary: 346.8 77.2% 49.8%; | ||||
|     --primary-foreground: 355.7 100% 97.3%; | ||||
|  | ||||
|     --secondary: 240 3.7% 15.9%; | ||||
|     --secondary-foreground: 0 0% 98%; | ||||
|  | ||||
|     --accent: 12 6.5% 15.1%; | ||||
|     --accent-foreground: 0 0% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 0 85.7% 97.3%; | ||||
|  | ||||
|     --ring: 346.8 77.2% 49.8%; | ||||
| } | ||||
|  | ||||
| .theme-orange { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --muted: 60 4.8% 95.9%; | ||||
|     --muted-foreground: 25 5.3% 44.7%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --border: 20 5.9% 90%; | ||||
|     --input: 20 5.9% 90%; | ||||
|  | ||||
|     --primary: 24.6 95% 53.1%; | ||||
|     --primary-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --secondary: 60 4.8% 95.9%; | ||||
|     --secondary-foreground: 24 9.8% 10%; | ||||
|  | ||||
|     --accent: 60 4.8% 95.9%; | ||||
|     --accent-foreground: 24 9.8% 10%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --ring: 24.6 95% 53.1%; | ||||
|  | ||||
|     --radius: 0.95rem; | ||||
| } | ||||
|  | ||||
| .theme-orange.dark { | ||||
|     --background: 20 14.3% 4.1%; | ||||
|     --foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --muted: 12 6.5% 15.1%; | ||||
|     --muted-foreground: 24 5.4% 63.9%; | ||||
|  | ||||
|     --popover: 20 14.3% 4.1%; | ||||
|     --popover-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --card: 20 14.3% 4.1%; | ||||
|     --card-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --border: 12 6.5% 15.1%; | ||||
|     --input: 12 6.5% 15.1%; | ||||
|  | ||||
|     --primary: 20.5 90.2% 48.2%; | ||||
|     --primary-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --secondary: 12 6.5% 15.1%; | ||||
|     --secondary-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --accent: 12 6.5% 15.1%; | ||||
|     --accent-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --destructive: 0 72.2% 50.6%; | ||||
|     --destructive-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --ring: 20.5 90.2% 48.2%; | ||||
| } | ||||
|  | ||||
| .theme-green { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --muted: 240 4.8% 95.9%; | ||||
|     --muted-foreground: 240 3.8% 46.1%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 240 10% 3.9%; | ||||
|  | ||||
|     --border: 240 5.9% 90%; | ||||
|     --input: 240 5.9% 90%; | ||||
|  | ||||
|     --primary: 142.1 76.2% 36.3%; | ||||
|     --primary-foreground: 355.7 100% 97.3%; | ||||
|  | ||||
|     --secondary: 240 4.8% 95.9%; | ||||
|     --secondary-foreground: 240 5.9% 10%; | ||||
|  | ||||
|     --accent: 240 4.8% 95.9%; | ||||
|     --accent-foreground: 240 5.9% 10%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 0 0% 98%; | ||||
|  | ||||
|     --ring: 142.1 76.2% 36.3%; | ||||
|  | ||||
|     --radius: ; | ||||
| } | ||||
|  | ||||
| .theme-green.dark { | ||||
|     --background: 20 14.3% 4.1%; | ||||
|     --foreground: 0 0% 95%; | ||||
|  | ||||
|     --muted: 0 0% 15%; | ||||
|     --muted-foreground: 240 5% 64.9%; | ||||
|  | ||||
|     --popover: 0 0% 9%; | ||||
|     --popover-foreground: 0 0% 95%; | ||||
|  | ||||
|     --card: 24 9.8% 10%; | ||||
|     --card-foreground: 0 0% 95%; | ||||
|  | ||||
|     --border: 240 3.7% 15.9%; | ||||
|     --input: 240 3.7% 15.9%; | ||||
|  | ||||
|     --primary: 142.1 70.6% 45.3%; | ||||
|     --primary-foreground: 144.9 80.4% 10%; | ||||
|  | ||||
|     --secondary: 240 3.7% 15.9%; | ||||
|     --secondary-foreground: 0 0% 98%; | ||||
|  | ||||
|     --accent: 12 6.5% 15.1%; | ||||
|     --accent-foreground: 0 0% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 0 85.7% 97.3%; | ||||
|  | ||||
|     --ring: 142.4 71.8% 29.2%; | ||||
| } | ||||
|  | ||||
| .theme-blue { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 222.2 84% 4.9%; | ||||
|  | ||||
|     --muted: 210 40% 96.1%; | ||||
|     --muted-foreground: 215.4 16.3% 46.9%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 222.2 84% 4.9%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 222.2 84% 4.9%; | ||||
|  | ||||
|     --border: 214.3 31.8% 91.4%; | ||||
|     --input: 214.3 31.8% 91.4%; | ||||
|  | ||||
|     --primary: 221.2 83.2% 53.3%; | ||||
|     --primary-foreground: 210 40% 98%; | ||||
|  | ||||
|     --secondary: 210 40% 96.1%; | ||||
|     --secondary-foreground: 222.2 47.4% 11.2%; | ||||
|  | ||||
|     --accent: 210 40% 96.1%; | ||||
|     --accent-foreground: 222.2 47.4% 11.2%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 210 40% 98%; | ||||
|  | ||||
|     --ring: 221.2 83.2% 53.3%; | ||||
|  | ||||
|     --radius: ; | ||||
| } | ||||
|  | ||||
| .theme-blue.dark { | ||||
|     --background: 222.2 84% 4.9%; | ||||
|     --foreground: 210 40% 98%; | ||||
|  | ||||
|     --muted: 217.2 32.6% 17.5%; | ||||
|     --muted-foreground: 215 20.2% 65.1%; | ||||
|  | ||||
|     --popover: 222.2 84% 4.9%; | ||||
|     --popover-foreground: 210 40% 98%; | ||||
|  | ||||
|     --card: 222.2 84% 4.9%; | ||||
|     --card-foreground: 210 40% 98%; | ||||
|  | ||||
|     --border: 217.2 32.6% 17.5%; | ||||
|     --input: 217.2 32.6% 17.5%; | ||||
|  | ||||
|     --primary: 217.2 91.2% 59.8%; | ||||
|     --primary-foreground: 222.2 47.4% 11.2%; | ||||
|  | ||||
|     --secondary: 217.2 32.6% 17.5%; | ||||
|     --secondary-foreground: 210 40% 98%; | ||||
|  | ||||
|     --accent: 217.2 32.6% 17.5%; | ||||
|     --accent-foreground: 210 40% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 210 40% 98%; | ||||
|  | ||||
|     --ring: 224.3 76.3% 48%; | ||||
| } | ||||
|  | ||||
| .theme-yellow { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --muted: 60 4.8% 95.9%; | ||||
|     --muted-foreground: 25 5.3% 44.7%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 20 14.3% 4.1%; | ||||
|  | ||||
|     --border: 20 5.9% 90%; | ||||
|     --input: 20 5.9% 90%; | ||||
|  | ||||
|     --primary: 47.9 95.8% 53.1%; | ||||
|     --primary-foreground: 26 83.3% 14.1%; | ||||
|  | ||||
|     --secondary: 60 4.8% 95.9%; | ||||
|     --secondary-foreground: 24 9.8% 10%; | ||||
|  | ||||
|     --accent: 60 4.8% 95.9%; | ||||
|     --accent-foreground: 24 9.8% 10%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --ring: 20 14.3% 4.1%; | ||||
|  | ||||
|     --radius: 0.95rem; | ||||
| } | ||||
|  | ||||
| .theme-yellow.dark { | ||||
|     --background: 20 14.3% 4.1%; | ||||
|     --foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --muted: 12 6.5% 15.1%; | ||||
|     --muted-foreground: 24 5.4% 63.9%; | ||||
|  | ||||
|     --popover: 20 14.3% 4.1%; | ||||
|     --popover-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --card: 20 14.3% 4.1%; | ||||
|     --card-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --border: 12 6.5% 15.1%; | ||||
|     --input: 12 6.5% 15.1%; | ||||
|  | ||||
|     --primary: 47.9 95.8% 53.1%; | ||||
|     --primary-foreground: 26 83.3% 14.1%; | ||||
|  | ||||
|     --secondary: 12 6.5% 15.1%; | ||||
|     --secondary-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --accent: 12 6.5% 15.1%; | ||||
|     --accent-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 60 9.1% 97.8%; | ||||
|  | ||||
|     --ring: 35.5 91.7% 32.9%; | ||||
| } | ||||
|  | ||||
| .theme-violet { | ||||
|     --background: 0 0% 100%; | ||||
|     --foreground: 224 71.4% 4.1%; | ||||
|  | ||||
|     --muted: 220 14.3% 95.9%; | ||||
|     --muted-foreground: 220 8.9% 46.1%; | ||||
|  | ||||
|     --popover: 0 0% 100%; | ||||
|     --popover-foreground: 224 71.4% 4.1%; | ||||
|  | ||||
|     --card: 0 0% 100%; | ||||
|     --card-foreground: 224 71.4% 4.1%; | ||||
|  | ||||
|     --border: 220 13% 91%; | ||||
|     --input: 220 13% 91%; | ||||
|  | ||||
|     --primary: 262.1 83.3% 57.8%; | ||||
|     --primary-foreground: 210 20% 98%; | ||||
|  | ||||
|     --secondary: 220 14.3% 95.9%; | ||||
|     --secondary-foreground: 220.9 39.3% 11%; | ||||
|  | ||||
|     --accent: 220 14.3% 95.9%; | ||||
|     --accent-foreground: 220.9 39.3% 11%; | ||||
|  | ||||
|     --destructive: 0 84.2% 60.2%; | ||||
|     --destructive-foreground: 210 20% 98%; | ||||
|  | ||||
|     --ring: 262.1 83.3% 57.8%; | ||||
|  | ||||
|     --radius: ; | ||||
| } | ||||
|  | ||||
| .theme-violet.dark { | ||||
|     --background: 224 71.4% 4.1%; | ||||
|     --foreground: 210 20% 98%; | ||||
|  | ||||
|     --muted: 215 27.9% 16.9%; | ||||
|     --muted-foreground: 217.9 10.6% 64.9%; | ||||
|  | ||||
|     --popover: 224 71.4% 4.1%; | ||||
|     --popover-foreground: 210 20% 98%; | ||||
|  | ||||
|     --card: 224 71.4% 4.1%; | ||||
|     --card-foreground: 210 20% 98%; | ||||
|  | ||||
|     --border: 215 27.9% 16.9%; | ||||
|     --input: 215 27.9% 16.9%; | ||||
|  | ||||
|     --primary: 263.4 70% 50.4%; | ||||
|     --primary-foreground: 210 20% 98%; | ||||
|  | ||||
|     --secondary: 215 27.9% 16.9%; | ||||
|     --secondary-foreground: 210 20% 98%; | ||||
|  | ||||
|     --accent: 215 27.9% 16.9%; | ||||
|     --accent-foreground: 210 20% 98%; | ||||
|  | ||||
|     --destructive: 0 62.8% 30.6%; | ||||
|     --destructive-foreground: 210 20% 98%; | ||||
|  | ||||
|     --ring: 263.4 70% 50.4%; | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								desktop/template/src/assets/fonts/Geist/GeistVariableVF.woff2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								desktop/template/src/assets/fonts/Geist/GeistVariableVF.woff2
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								desktop/template/src/assets/image/wechat_code.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								desktop/template/src/assets/image/wechat_code.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 53 KiB | 
| @@ -1,34 +0,0 @@ | ||||
| import { type VariantProps, cva } from 'class-variance-authority' | ||||
|  | ||||
| export { default as Button } from './Button.vue' | ||||
|  | ||||
| export const buttonVariants = cva( | ||||
|   'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', | ||||
|   { | ||||
|     variants: { | ||||
|       variant: { | ||||
|         default: 'bg-primary text-primary-foreground hover:bg-primary/90', | ||||
|         destructive: | ||||
|           'bg-destructive text-destructive-foreground hover:bg-destructive/90', | ||||
|         outline: | ||||
|           'border border-input bg-background hover:bg-accent hover:text-accent-foreground', | ||||
|         secondary: | ||||
|           'bg-secondary text-secondary-foreground hover:bg-secondary/80', | ||||
|         ghost: 'hover:bg-accent hover:text-accent-foreground', | ||||
|         link: 'text-primary underline-offset-4 hover:underline', | ||||
|       }, | ||||
|       size: { | ||||
|         default: 'h-10 px-4 py-2', | ||||
|         sm: 'h-9 rounded-md px-3', | ||||
|         lg: 'h-11 rounded-md px-8', | ||||
|         icon: 'h-10 w-10', | ||||
|       }, | ||||
|     }, | ||||
|     defaultVariants: { | ||||
|       variant: 'default', | ||||
|       size: 'default', | ||||
|     }, | ||||
|   }, | ||||
| ) | ||||
|  | ||||
| export type ButtonVariants = VariantProps<typeof buttonVariants> | ||||
| @@ -1,33 +1,12 @@ | ||||
| import {createApp} from "vue"; | ||||
| import App from "./app.vue"; | ||||
| import {router} from "./router"; | ||||
| import {Router} from "./packages/router"; | ||||
| import {Language} from "./packages/language"; | ||||
|  | ||||
| const app = createApp(App); | ||||
|  | ||||
| app.use(router); | ||||
| app.use(Router); | ||||
|  | ||||
| app.directive("resize", { | ||||
|     mounted(el, binding) { | ||||
|         let _this: any = this; | ||||
|         function debounce(fn: any, delay = 16) { | ||||
|             let time: any = null; | ||||
|             return function () { | ||||
|                 if (time) { | ||||
|                     clearTimeout(time); | ||||
|                 } | ||||
|                 const context = _this; | ||||
|                 const args = arguments | ||||
|                 time = setTimeout(function () { | ||||
|                     fn.apply(context, args); | ||||
|                 }, delay); | ||||
|             } | ||||
|         } | ||||
|         el._resizer = new window.ResizeObserver(debounce(binding.value, Number(binding.arg) || 16)); | ||||
|         el._resizer.observe(el); | ||||
|     }, | ||||
|     unmounted(el) { | ||||
|         el._resizer.disconnect(); | ||||
|     } | ||||
| }); | ||||
| app.use(Language); | ||||
|  | ||||
| app.mount("#app"); | ||||
|   | ||||
| @@ -1,6 +0,0 @@ | ||||
| import { type ClassValue, clsx } from "clsx"; | ||||
| import { twMerge } from "tailwind-merge"; | ||||
|  | ||||
| export function cn(...inputs: ClassValue[]) { | ||||
|     return twMerge(clsx(inputs)) | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL | ||||
| // This file is automatically generated. DO NOT EDIT | ||||
|  | ||||
| export function GetPlatform():Promise<string>; | ||||
|  | ||||
| export function GetVersion():Promise<Array<string>>; | ||||
| @@ -1,11 +0,0 @@ | ||||
| // @ts-check | ||||
| // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL | ||||
| // This file is automatically generated. DO NOT EDIT | ||||
|  | ||||
| export function GetPlatform() { | ||||
|   return window['go']['StartWindows']['Api']['GetPlatform'](); | ||||
| } | ||||
|  | ||||
| export function GetVersion() { | ||||
|   return window['go']['StartWindows']['Api']['GetVersion'](); | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| { | ||||
|   "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" | ||||
| } | ||||
| @@ -1,235 +0,0 @@ | ||||
| /* | ||||
|  _       __      _ __ | ||||
| | |     / /___ _(_) /____ | ||||
| | | /| / / __ `/ / / ___/ | ||||
| | |/ |/ / /_/ / / (__  ) | ||||
| |__/|__/\__,_/_/_/____/ | ||||
| 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): Promise<Size>; | ||||
|  | ||||
| // [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>; | ||||
| @@ -1,202 +0,0 @@ | ||||
| /* | ||||
|  _       __      _ __ | ||||
| | |     / /___ _(_) /____ | ||||
| | | /| / / __ `/ / / ___/ | ||||
| | |/ |/ / /_/ / / (__  ) | ||||
| |__/|__/\__,_/_/_/____/ | ||||
| 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 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); | ||||
| } | ||||
							
								
								
									
										3
									
								
								desktop/template/src/packages/config/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								desktop/template/src/packages/config/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| type Color = | 'zinc' | 'slate' | 'stone' | 'gray' | 'neutral' | 'red' | 'rose' | 'orange' | 'green' | 'blue' | 'yellow' | 'violet'; | ||||
|  | ||||
| export const ThemeColors: Color[] = ["zinc", "rose", "blue", "green", "orange", "red", "slate", "stone", "gray", "neutral", "yellow", "violet"]; | ||||
							
								
								
									
										16
									
								
								desktop/template/src/packages/flow/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								desktop/template/src/packages/flow/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| import {shallowRef} from "vue"; | ||||
| import {Start, StartNode} from "./node/start"; | ||||
|  | ||||
| export const Types = { | ||||
|     start: shallowRef(Start), | ||||
| }; | ||||
|  | ||||
| export const Nodes = [ | ||||
|     StartNode, | ||||
| ]; | ||||
|  | ||||
| export {VueFlow, Panel, useVueFlow} from "@vue-flow/core"; | ||||
| export {Controls, ControlButton} from "@vue-flow/controls"; | ||||
| export {NodeToolbar} from "@vue-flow/node-toolbar"; | ||||
| export {Background} from "@vue-flow/background"; | ||||
| export {MiniMap} from "@vue-flow/minimap"; | ||||
							
								
								
									
										10
									
								
								desktop/template/src/packages/flow/node/start/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								desktop/template/src/packages/flow/node/start/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| export { default as Start } from "./index.vue"; | ||||
|  | ||||
| export const StartNode = { | ||||
|     id: "121212", | ||||
|     type: "start", | ||||
|     data: { | ||||
|         label: "开始对话", | ||||
|     }, | ||||
|     position: {x: 250, y: 0} | ||||
| }; | ||||
							
								
								
									
										60
									
								
								desktop/template/src/packages/flow/node/start/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								desktop/template/src/packages/flow/node/start/index.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| <template> | ||||
|     <div class="w-auto text-sm shadow-sm"> | ||||
|         <NodeToolbar align="end" offset="5" :is-visible="props.data.toolbarVisible" :position="Position.Top"> | ||||
|             <Button class="w-8 h-8 bg-background" variant="secondary" size="icon"> | ||||
|                 <DotsVerticalIcon class="w-3 h-3" /> | ||||
|             </Button> | ||||
|         </NodeToolbar> | ||||
|         <ContextMenu> | ||||
|             <ContextMenuTrigger> | ||||
|                 <div class="w-auto h-auto p-3 rounded-md space-y-3"> | ||||
|                     <div class="w-full flex space-x-2 items-center text-xs"> | ||||
|                         <div class="w-6 h-6"> | ||||
|                             <Button class="w-6 h-6 text-xs" size="icon"> | ||||
|                                 <PlayIcon class="w-3 h-3" /> | ||||
|                             </Button> | ||||
|                         </div> | ||||
|                         <div class="w-[120px] line-clamp-1">{{props.data.label}}</div> | ||||
|                     </div> | ||||
|                     <div class="relative min-h-6 flex items-center"> | ||||
|                         <div class="w-full"></div> | ||||
|                         <Handle id="a" type="target" :position="Position.Right"></Handle> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </ContextMenuTrigger> | ||||
|             <ContextMenuContent class="hidden"></ContextMenuContent> | ||||
|         </ContextMenu> | ||||
|     </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import {onBeforeMount, onMounted, onBeforeUnmount, onUnmounted, nextTick} from "vue"; | ||||
| import {Handle, Position} from "@vue-flow/core"; | ||||
| import {NodeToolbar} from "@vue-flow/node-toolbar"; | ||||
| import {Button} from "@/lib/button"; | ||||
| import {DotsVerticalIcon, PlayIcon} from "@radix-icons/vue"; | ||||
| import {ContextMenu, ContextMenuContent, ContextMenuTrigger} from "@/lib/context-menu"; | ||||
|  | ||||
| const props = defineProps({ | ||||
|     id: { | ||||
|         type: String, | ||||
|         required: true, | ||||
|     }, | ||||
|     data: { | ||||
|         type: Object, | ||||
|         required: true, | ||||
|     } | ||||
| }); | ||||
|  | ||||
| onBeforeMount(() => {}); | ||||
|  | ||||
| onMounted(() => { | ||||
|     nextTick(() => { | ||||
|  | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| onBeforeUnmount(() => {}); | ||||
|  | ||||
| onUnmounted(() => {}); | ||||
| </script> | ||||
							
								
								
									
										9
									
								
								desktop/template/src/packages/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								desktop/template/src/packages/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| export {useRoute, useRouter} from "vue-router"; | ||||
| export {useI18n} from "vue-i18n"; | ||||
| export {useDark} from "@vueuse/core"; | ||||
| export {useStore} from "./store"; | ||||
| export {Request} from "./request"; | ||||
| export {useForm} from "vee-validate"; | ||||
| export {toTypedSchema} from "@vee-validate/zod"; | ||||
| export {object, string} from "zod"; | ||||
| export {ThemeColors} from "./config"; | ||||
							
								
								
									
										82
									
								
								desktop/template/src/packages/language/en/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								desktop/template/src/packages/language/en/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| export default { | ||||
|     header: { | ||||
|         search: { | ||||
|             tooltip: "Search" | ||||
|         }, | ||||
|         tab: { | ||||
|             dashboard: "Dashboard", | ||||
|             account: "Account", | ||||
|             assets: "Assets", | ||||
|             operate: "Operate", | ||||
|             tools: "Tools" | ||||
|         }, | ||||
|         theme: { | ||||
|             tooltip: "Theme Customizing", | ||||
|             title: "Customize", | ||||
|             describe: "Pick a style and color for your components", | ||||
|             colour: "Colour", | ||||
|             fillet: "Fillet", | ||||
|             style: "Style" | ||||
|         }, | ||||
|         user: { | ||||
|             profile: "Your Profile", | ||||
|             member: "Member Management", | ||||
|             settings: "Settings", | ||||
|             upgrade: "Upgrade Subscribe", | ||||
|             logout: "Log out" | ||||
|         } | ||||
|     }, | ||||
|     page: { | ||||
|         login: { | ||||
|             title: "Connect to Server", | ||||
|             describe: "Enter your server information below and connect", | ||||
|             email: "Email", | ||||
|             password: "Password", | ||||
|             forgot_password: "Forgot your password?", | ||||
|             button: "Sign in", | ||||
|             account: "Don't have an account?", | ||||
|             register: { | ||||
|                 email: "Email", | ||||
|                 code: { | ||||
|                     title: "Captcha", | ||||
|                     button: "Get Captcha", | ||||
|                     loading: "Retry in {count} second" | ||||
|                 }, | ||||
|                 password: "Password", | ||||
|                 button: "Sign up", | ||||
|                 account: "Already have an account?" | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
|     common: { | ||||
|         tooltips: "ToolTips", | ||||
|         nodata: "No relevant data", | ||||
|         abnormal: "Service request exception", | ||||
|         incomplete_information: "Incomplete information", | ||||
|         search: { | ||||
|             keyword: "Search keyword..." | ||||
|         }, | ||||
|         select: { | ||||
|             placeholder: "Select" | ||||
|         }, | ||||
|         alert: { | ||||
|             delete: "Delete this data?", | ||||
|             cancel: "Cancel", | ||||
|             confirm: "Confirm" | ||||
|         }, | ||||
|         status: { | ||||
|             success: "Request successful", | ||||
|             error: "Request failed, please try again", | ||||
|             20000: "Request failed, please try again", | ||||
|             20001: "Please fill in the correct email address", | ||||
|             20002: "Please fill in the login password", | ||||
|             20003: "Please confirm the login password", | ||||
|             20004: "Inconsistent password input", | ||||
|             20005: "Please fill in the correct verification code", | ||||
|             20006: "Login email or password error", | ||||
|             20007: "Email verification code error", | ||||
|             20008: "The email has been registered", | ||||
|             20009: "Please provide the correct server address", | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										28
									
								
								desktop/template/src/packages/language/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								desktop/template/src/packages/language/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| import {createI18n} from "vue-i18n"; | ||||
| import en from "./en"; | ||||
| import zh from './zh'; | ||||
|  | ||||
| const messages = { | ||||
|     en: en, | ||||
|     zh: zh | ||||
| }; | ||||
|  | ||||
| function init(){ | ||||
|     let lang: string = "zh"; | ||||
|  | ||||
|     if(localStorage.getItem("mir2:language")){ | ||||
|         lang = localStorage.getItem("mir2:language") + "" | ||||
|     }else{ | ||||
|         localStorage.setItem("mir2:language", "zh") | ||||
|     } | ||||
|  | ||||
|     return lang | ||||
| } | ||||
|  | ||||
| export const Language = createI18n({ | ||||
|     legacy: false, | ||||
|     locale: init(), | ||||
|     fallbackLocale: "zh", | ||||
|     messages, | ||||
|     warnHtmlMessage: false | ||||
| }); | ||||
							
								
								
									
										82
									
								
								desktop/template/src/packages/language/zh/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								desktop/template/src/packages/language/zh/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| export default { | ||||
|     header: { | ||||
|         search: { | ||||
|             tooltip: "搜索" | ||||
|         }, | ||||
|         tab: { | ||||
|             dashboard: "仪表盘", | ||||
|             account: "用户管理", | ||||
|             assets: "游戏资产", | ||||
|             operate: "运营维护", | ||||
|             tools: "工具箱" | ||||
|         }, | ||||
|         theme: { | ||||
|             tooltip: "主题定制", | ||||
|             title: "自定义", | ||||
|             describe: "为零部件选择样式和颜色", | ||||
|             colour: "颜色", | ||||
|             fillet: "圆角", | ||||
|             style: "样式" | ||||
|         }, | ||||
|         user: { | ||||
|             profile: "个人资料", | ||||
|             member: "学科&学生管理", | ||||
|             settings: "设置", | ||||
|             upgrade: "升级套餐", | ||||
|             logout: "退出登录" | ||||
|         } | ||||
|     }, | ||||
|     page: { | ||||
|         login: { | ||||
|             title: "连接服务器", | ||||
|             describe: "在下面输入您的服务器信息并连接", | ||||
|             email: "邮箱", | ||||
|             password: "密码", | ||||
|             forgot_password: "忘记密码?", | ||||
|             button: "登录", | ||||
|             account: "没有账号?", | ||||
|             register: { | ||||
|                 email: "邮箱", | ||||
|                 code: { | ||||
|                     title: "验证码", | ||||
|                     button: "获取验证码", | ||||
|                     loading: "{count}秒后重试" | ||||
|                 }, | ||||
|                 password: "密码", | ||||
|                 button: "注册", | ||||
|                 account: "已有账号?" | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
|     common: { | ||||
|         tooltips: "提示", | ||||
|         nodata: "没有相关数据", | ||||
|         abnormal: "服务请求异常", | ||||
|         incomplete_information: "信息不完整", | ||||
|         search: { | ||||
|             keyword: "搜索关键词..." | ||||
|         }, | ||||
|         select: { | ||||
|             placeholder: "选择" | ||||
|         }, | ||||
|         alert: { | ||||
|             delete: "是否删除这条数据", | ||||
|             cancel: "取消", | ||||
|             confirm: "确定" | ||||
|         }, | ||||
|         status: { | ||||
|             success: "请求成功", | ||||
|             error: "请求失败,请重新尝试", | ||||
|             20000: "请求失败,请重新尝试", | ||||
|             20001: "请填写正确的邮箱", | ||||
|             20002: "请填写登录密码", | ||||
|             20003: "请确认登录密码", | ||||
|             20004: "两次密码不一致", | ||||
|             20005: "请填写正确的验证码", | ||||
|             20006: "登录邮箱或密码错误", | ||||
|             20007: "邮箱验证码错误", | ||||
|             20008: "邮箱已经被注册", | ||||
|             20009: "请填写正确的服务器地址", | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										62
									
								
								desktop/template/src/packages/request/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								desktop/template/src/packages/request/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| import Axios from "axios"; | ||||
| import FingerprintJS from "@fingerprintjs/fingerprintjs"; | ||||
|  | ||||
| const request = Axios.create({ | ||||
|     baseURL: "", | ||||
|     timeout: 15000, | ||||
| }); | ||||
|  | ||||
| request.interceptors.response.use( | ||||
|     response => { | ||||
|         if (response.status === 200) { | ||||
|             return Promise.resolve(response); | ||||
|         } else { | ||||
|             return Promise.reject(response); | ||||
|         } | ||||
|     }, | ||||
|     error => { | ||||
|         if(error.response){ | ||||
|             if (error.response.status) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| ); | ||||
|  | ||||
| export async function Request(path: string, method: string, params: object, data: object) { | ||||
|     const baseURL: string = "https://api.mir2.geekros.com"; | ||||
|     return FingerprintJS.load().then((fp: any) => { | ||||
|         return fp.get().then((result: any) => { | ||||
|             return request({ | ||||
|                 baseURL: baseURL, | ||||
|                 headers: { | ||||
|                     "Content-Type": "application/json", | ||||
|                     "Accept-Fetch-Id": "desktop", | ||||
|                     "Accept-Fetch-Referer": "makeryang.com", | ||||
|                     "Accept-Fetch-Visitor": result.visitorId, | ||||
|                     "Accept-Fetch-Auth": localStorage.getItem("mir2:login:token") ? localStorage.getItem("mir2:login:token") : "" | ||||
|                 }, | ||||
|                 url: path, | ||||
|                 method: method, | ||||
|                 params: params ? params : {}, | ||||
|                 data: data ? data : {} | ||||
|             }); | ||||
|         }); | ||||
|     }).catch(()=>{ | ||||
|         return request({ | ||||
|             baseURL: baseURL, | ||||
|             headers: { | ||||
|                 "Content-Type": "application/json", | ||||
|                 "Accept-Fetch-Id": "desktop", | ||||
|                 "Accept-Fetch-Referer": "makeryang.com", | ||||
|                 "Accept-Fetch-Visitor": "", | ||||
|                 "Accept-Fetch-Auth": "" | ||||
|             }, | ||||
|             url: path, | ||||
|             method: method, | ||||
|             params: params ? params : {}, | ||||
|             data: data ? data : {} | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
							
								
								
									
										15
									
								
								desktop/template/src/packages/router/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								desktop/template/src/packages/router/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| import {createRouter, createWebHashHistory } from "vue-router"; | ||||
| import Start from "../../pages/start.vue"; | ||||
|  | ||||
| const routes: any = [ | ||||
|     { | ||||
|         path: "/", | ||||
|         name: "Start", | ||||
|         component: Start | ||||
|     } | ||||
| ] | ||||
|  | ||||
| export const Router = createRouter({ | ||||
|     history: createWebHashHistory(), | ||||
|     routes: routes | ||||
| }); | ||||
							
								
								
									
										19
									
								
								desktop/template/src/packages/shadcn/accordion/Accordion.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								desktop/template/src/packages/shadcn/accordion/Accordion.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| <script setup lang="ts"> | ||||
| import { | ||||
|   AccordionRoot, | ||||
|   type AccordionRootEmits, | ||||
|   type AccordionRootProps, | ||||
|   useForwardPropsEmits, | ||||
| } from 'radix-vue' | ||||
|  | ||||
| const props = defineProps<AccordionRootProps>() | ||||
| const emits = defineEmits<AccordionRootEmits>() | ||||
|  | ||||
| const forwarded = useForwardPropsEmits(props, emits) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AccordionRoot v-bind="forwarded"> | ||||
|     <slot /> | ||||
|   </AccordionRoot> | ||||
| </template> | ||||
| @@ -0,0 +1,24 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { AccordionContent, type AccordionContentProps } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<AccordionContentProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AccordionContent | ||||
|     v-bind="delegatedProps" | ||||
|     class="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down" | ||||
|   > | ||||
|     <div :class="cn('pb-4 pt-0', props.class)"> | ||||
|       <slot /> | ||||
|     </div> | ||||
|   </AccordionContent> | ||||
| </template> | ||||
| @@ -0,0 +1,24 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { AccordionItem, type AccordionItemProps, useForwardProps } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
|  | ||||
| const forwardedProps = useForwardProps(delegatedProps) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AccordionItem | ||||
|     v-bind="forwardedProps" | ||||
|     :class="cn('border-b', props.class)" | ||||
|   > | ||||
|     <slot /> | ||||
|   </AccordionItem> | ||||
| </template> | ||||
| @@ -0,0 +1,39 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { | ||||
|   AccordionHeader, | ||||
|   AccordionTrigger, | ||||
|   type AccordionTriggerProps, | ||||
| } from 'radix-vue' | ||||
| import { ChevronDownIcon } from '@radix-icons/vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AccordionHeader class="flex"> | ||||
|     <AccordionTrigger | ||||
|       v-bind="delegatedProps" | ||||
|       :class=" | ||||
|         cn( | ||||
|           'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180', | ||||
|           props.class, | ||||
|         ) | ||||
|       " | ||||
|     > | ||||
|       <slot /> | ||||
|       <slot name="icon"> | ||||
|         <ChevronDownIcon | ||||
|           class="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" | ||||
|         /> | ||||
|       </slot> | ||||
|     </AccordionTrigger> | ||||
|   </AccordionHeader> | ||||
| </template> | ||||
							
								
								
									
										4
									
								
								desktop/template/src/packages/shadcn/accordion/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								desktop/template/src/packages/shadcn/accordion/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| export { default as Accordion } from './Accordion.vue' | ||||
| export { default as AccordionContent } from './AccordionContent.vue' | ||||
| export { default as AccordionItem } from './AccordionItem.vue' | ||||
| export { default as AccordionTrigger } from './AccordionTrigger.vue' | ||||
| @@ -0,0 +1,14 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type AlertDialogEmits, type AlertDialogProps, AlertDialogRoot, useForwardPropsEmits } from 'radix-vue' | ||||
|  | ||||
| const props = defineProps<AlertDialogProps>() | ||||
| const emits = defineEmits<AlertDialogEmits>() | ||||
|  | ||||
| const forwarded = useForwardPropsEmits(props, emits) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AlertDialogRoot v-bind="forwarded"> | ||||
|     <slot /> | ||||
|   </AlertDialogRoot> | ||||
| </template> | ||||
| @@ -0,0 +1,20 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { AlertDialogAction, type AlertDialogActionProps } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
| import { buttonVariants } from '@/lib/button' | ||||
|  | ||||
| const props = defineProps<AlertDialogActionProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AlertDialogAction v-bind="delegatedProps" :class="cn(buttonVariants(), props.class)"> | ||||
|     <slot /> | ||||
|   </AlertDialogAction> | ||||
| </template> | ||||
| @@ -0,0 +1,20 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { AlertDialogCancel, type AlertDialogCancelProps } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
| import { buttonVariants } from '@/lib/button' | ||||
|  | ||||
| const props = defineProps<AlertDialogCancelProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AlertDialogCancel v-bind="delegatedProps" :class="cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', props.class)"> | ||||
|     <slot /> | ||||
|   </AlertDialogCancel> | ||||
| </template> | ||||
| @@ -0,0 +1,42 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { | ||||
|   AlertDialogContent, | ||||
|   type AlertDialogContentEmits, | ||||
|   type AlertDialogContentProps, | ||||
|   AlertDialogOverlay, | ||||
|   AlertDialogPortal, | ||||
|   useForwardPropsEmits, | ||||
| } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<AlertDialogContentProps & { class?: HTMLAttributes['class'] }>() | ||||
| const emits = defineEmits<AlertDialogContentEmits>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
|  | ||||
| const forwarded = useForwardPropsEmits(delegatedProps, emits) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AlertDialogPortal> | ||||
|     <AlertDialogOverlay | ||||
|       class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" | ||||
|     /> | ||||
|     <AlertDialogContent | ||||
|       v-bind="forwarded" | ||||
|       :class=" | ||||
|         cn( | ||||
|           'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg', | ||||
|           props.class, | ||||
|         ) | ||||
|       " | ||||
|     > | ||||
|       <slot /> | ||||
|     </AlertDialogContent> | ||||
|   </AlertDialogPortal> | ||||
| </template> | ||||
| @@ -0,0 +1,25 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { | ||||
|   AlertDialogDescription, | ||||
|   type AlertDialogDescriptionProps, | ||||
| } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<AlertDialogDescriptionProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AlertDialogDescription | ||||
|     v-bind="delegatedProps" | ||||
|     :class="cn('text-sm text-muted-foreground', props.class)" | ||||
|   > | ||||
|     <slot /> | ||||
|   </AlertDialogDescription> | ||||
| </template> | ||||
| @@ -0,0 +1,21 @@ | ||||
| <script setup lang="ts"> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div | ||||
|     :class=" | ||||
|       cn( | ||||
|         'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2', | ||||
|         props.class, | ||||
|       ) | ||||
|     " | ||||
|   > | ||||
|     <slot /> | ||||
|   </div> | ||||
| </template> | ||||
| @@ -0,0 +1,16 @@ | ||||
| <script setup lang="ts"> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div | ||||
|     :class="cn('flex flex-col gap-y-2 text-center sm:text-left', props.class)" | ||||
|   > | ||||
|     <slot /> | ||||
|   </div> | ||||
| </template> | ||||
| @@ -0,0 +1,22 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { AlertDialogTitle, type AlertDialogTitleProps } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<AlertDialogTitleProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AlertDialogTitle | ||||
|     v-bind="delegatedProps" | ||||
|     :class="cn('text-lg font-semibold', props.class)" | ||||
|   > | ||||
|     <slot /> | ||||
|   </AlertDialogTitle> | ||||
| </template> | ||||
| @@ -0,0 +1,11 @@ | ||||
| <script setup lang="ts"> | ||||
| import { AlertDialogTrigger, type AlertDialogTriggerProps } from 'radix-vue' | ||||
|  | ||||
| const props = defineProps<AlertDialogTriggerProps>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AlertDialogTrigger v-bind="props"> | ||||
|     <slot /> | ||||
|   </AlertDialogTrigger> | ||||
| </template> | ||||
| @@ -0,0 +1,9 @@ | ||||
| export { default as AlertDialog } from './AlertDialog.vue' | ||||
| export { default as AlertDialogTrigger } from './AlertDialogTrigger.vue' | ||||
| export { default as AlertDialogContent } from './AlertDialogContent.vue' | ||||
| export { default as AlertDialogHeader } from './AlertDialogHeader.vue' | ||||
| export { default as AlertDialogTitle } from './AlertDialogTitle.vue' | ||||
| export { default as AlertDialogDescription } from './AlertDialogDescription.vue' | ||||
| export { default as AlertDialogFooter } from './AlertDialogFooter.vue' | ||||
| export { default as AlertDialogAction } from './AlertDialogAction.vue' | ||||
| export { default as AlertDialogCancel } from './AlertDialogCancel.vue' | ||||
							
								
								
									
										16
									
								
								desktop/template/src/packages/shadcn/alert/Alert.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								desktop/template/src/packages/shadcn/alert/Alert.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <script setup lang="ts"> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { type AlertVariants, alertVariants } from '.' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
|   variant?: AlertVariants['variant'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div :class="cn(alertVariants({ variant }), props.class)" role="alert"> | ||||
|     <slot /> | ||||
|   </div> | ||||
| </template> | ||||
| @@ -0,0 +1,14 @@ | ||||
| <script setup lang="ts"> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div :class="cn('text-sm [&_p]:leading-relaxed', props.class)"> | ||||
|     <slot /> | ||||
|   </div> | ||||
| </template> | ||||
							
								
								
									
										14
									
								
								desktop/template/src/packages/shadcn/alert/AlertTitle.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								desktop/template/src/packages/shadcn/alert/AlertTitle.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| <script setup lang="ts"> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <h5 :class="cn('mb-1 font-medium leading-none tracking-tight', props.class)"> | ||||
|     <slot /> | ||||
|   </h5> | ||||
| </template> | ||||
							
								
								
									
										23
									
								
								desktop/template/src/packages/shadcn/alert/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								desktop/template/src/packages/shadcn/alert/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| import { type VariantProps, cva } from 'class-variance-authority' | ||||
|  | ||||
| export { default as Alert } from './Alert.vue' | ||||
| export { default as AlertTitle } from './AlertTitle.vue' | ||||
| export { default as AlertDescription } from './AlertDescription.vue' | ||||
|  | ||||
| export const alertVariants = cva( | ||||
|   'relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7', | ||||
|   { | ||||
|     variants: { | ||||
|       variant: { | ||||
|         default: 'bg-background text-foreground', | ||||
|         destructive: | ||||
|           'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive', | ||||
|       }, | ||||
|     }, | ||||
|     defaultVariants: { | ||||
|       variant: 'default', | ||||
|     }, | ||||
|   }, | ||||
| ) | ||||
|  | ||||
| export type AlertVariants = VariantProps<typeof alertVariants> | ||||
| @@ -0,0 +1,11 @@ | ||||
| <script setup lang="ts"> | ||||
| import { AspectRatio, type AspectRatioProps } from 'radix-vue' | ||||
|  | ||||
| const props = defineProps<AspectRatioProps>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AspectRatio v-bind="props"> | ||||
|     <slot /> | ||||
|   </AspectRatio> | ||||
| </template> | ||||
| @@ -0,0 +1 @@ | ||||
| export { default as AspectRatio } from './AspectRatio.vue' | ||||
							
								
								
									
										105
									
								
								desktop/template/src/packages/shadcn/auto-form/AutoForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								desktop/template/src/packages/shadcn/auto-form/AutoForm.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| <script setup lang="ts" generic="T extends ZodObjectOrWrapped"> | ||||
| import { computed, toRefs } from 'vue' | ||||
| import type { ZodAny, z } from 'zod' | ||||
| import { toTypedSchema } from '@vee-validate/zod' | ||||
| import type { FormContext, GenericObject } from 'vee-validate' | ||||
| import { type ZodObjectOrWrapped, getBaseSchema, getBaseType, getDefaultValueInZodStack, getObjectFormSchema } from './utils' | ||||
| import type { Config, ConfigItem, Dependency, Shape } from './interface' | ||||
| import AutoFormField from './AutoFormField.vue' | ||||
| import { provideDependencies } from './dependencies' | ||||
| import { Form } from '@/lib/registry/new-york/ui/form' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   schema: T | ||||
|   form?: FormContext<GenericObject> | ||||
|   fieldConfig?: Config<z.infer<T>> | ||||
|   dependencies?: Dependency<z.infer<T>>[] | ||||
| }>() | ||||
|  | ||||
| const emits = defineEmits<{ | ||||
|   submit: [event: GenericObject] | ||||
| }>() | ||||
|  | ||||
| const { dependencies } = toRefs(props) | ||||
| provideDependencies(dependencies) | ||||
|  | ||||
| const shapes = computed(() => { | ||||
|   // @ts-expect-error ignore {} not assignable to object | ||||
|   const val: { [key in keyof T]: Shape } = {} | ||||
|   const baseSchema = getObjectFormSchema(props.schema) | ||||
|   const shape = baseSchema.shape | ||||
|   Object.keys(shape).forEach((name) => { | ||||
|     const item = shape[name] as ZodAny | ||||
|     const baseItem = getBaseSchema(item) as ZodAny | ||||
|     let options = (baseItem && 'values' in baseItem._def) ? baseItem._def.values as string[] : undefined | ||||
|     if (!Array.isArray(options) && typeof options === 'object') | ||||
|       options = Object.values(options) | ||||
|  | ||||
|     val[name as keyof T] = { | ||||
|       type: getBaseType(item), | ||||
|       default: getDefaultValueInZodStack(item), | ||||
|       options, | ||||
|       required: !['ZodOptional', 'ZodNullable'].includes(item._def.typeName), | ||||
|       schema: baseItem, | ||||
|     } | ||||
|   }) | ||||
|   return val | ||||
| }) | ||||
|  | ||||
| const fields = computed(() => { | ||||
|   // @ts-expect-error ignore {} not assignable to object | ||||
|   const val: { [key in keyof z.infer<T>]: { shape: Shape, fieldName: string, config: ConfigItem } } = {} | ||||
|   for (const key in shapes.value) { | ||||
|     const shape = shapes.value[key] | ||||
|     val[key as keyof z.infer<T>] = { | ||||
|       shape, | ||||
|       config: props.fieldConfig?.[key] as ConfigItem, | ||||
|       fieldName: key, | ||||
|     } | ||||
|   } | ||||
|   return val | ||||
| }) | ||||
|  | ||||
| const formComponent = computed(() => props.form ? 'form' : Form) | ||||
| const formComponentProps = computed(() => { | ||||
|   if (props.form) { | ||||
|     return { | ||||
|       onSubmit: props.form.handleSubmit(val => emits('submit', val)), | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     const formSchema = toTypedSchema(props.schema) | ||||
|     return { | ||||
|       keepValues: true, | ||||
|       validationSchema: formSchema, | ||||
|       onSubmit: (val: GenericObject) => emits('submit', val), | ||||
|     } | ||||
|   } | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <component | ||||
|     :is="formComponent" | ||||
|     v-bind="formComponentProps" | ||||
|   > | ||||
|     <slot name="customAutoForm" :fields="fields"> | ||||
|       <template v-for="(shape, key) of shapes" :key="key"> | ||||
|         <slot | ||||
|           :shape="shape" | ||||
|           :name="key.toString() as keyof z.infer<T>" | ||||
|           :field-name="key.toString()" | ||||
|           :config="fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem" | ||||
|         > | ||||
|           <AutoFormField | ||||
|             :config="fieldConfig?.[key as keyof typeof fieldConfig] as ConfigItem" | ||||
|             :field-name="key.toString()" | ||||
|             :shape="shape" | ||||
|           /> | ||||
|         </slot> | ||||
|       </template> | ||||
|     </slot> | ||||
|  | ||||
|     <slot :shapes="shapes" /> | ||||
|   </component> | ||||
| </template> | ||||
| @@ -0,0 +1,45 @@ | ||||
| <script setup lang="ts" generic="U extends ZodAny"> | ||||
| import type { ZodAny } from 'zod' | ||||
| import { computed } from 'vue' | ||||
| import type { Config, ConfigItem, Shape } from './interface' | ||||
| import { DEFAULT_ZOD_HANDLERS, INPUT_COMPONENTS } from './constant' | ||||
| import useDependencies from './dependencies' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   fieldName: string | ||||
|   shape: Shape | ||||
|   config?: ConfigItem | Config<U> | ||||
| }>() | ||||
|  | ||||
| function isValidConfig(config: any): config is ConfigItem { | ||||
|   return !!config?.component | ||||
| } | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   if (['ZodObject', 'ZodArray'].includes(props.shape?.type)) | ||||
|     return { schema: props.shape?.schema } | ||||
|   return undefined | ||||
| }) | ||||
|  | ||||
| const { isDisabled, isHidden, isRequired, overrideOptions } = useDependencies(props.fieldName) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <component | ||||
|     :is="isValidConfig(config) | ||||
|       ? typeof config.component === 'string' | ||||
|         ? INPUT_COMPONENTS[config.component!] | ||||
|         : config.component | ||||
|       : INPUT_COMPONENTS[DEFAULT_ZOD_HANDLERS[shape.type]] " | ||||
|     v-if="!isHidden" | ||||
|     :field-name="fieldName" | ||||
|     :label="shape.schema?.description" | ||||
|     :required="isRequired || shape.required" | ||||
|     :options="overrideOptions || shape.options" | ||||
|     :disabled="isDisabled" | ||||
|     :config="config" | ||||
|     v-bind="delegatedProps" | ||||
|   > | ||||
|     <slot /> | ||||
|   </component> | ||||
| </template> | ||||
| @@ -0,0 +1,110 @@ | ||||
| <script setup lang="ts" generic="T extends z.ZodAny"> | ||||
| import * as z from 'zod' | ||||
| import { computed, provide } from 'vue' | ||||
| import { PlusIcon, TrashIcon } from 'lucide-vue-next' | ||||
| import { FieldArray, FieldContextKey, useField } from 'vee-validate' | ||||
| import type { Config, ConfigItem } from './interface' | ||||
| import { beautifyObjectName, getBaseType } from './utils' | ||||
| import AutoFormField from './AutoFormField.vue' | ||||
| import AutoFormLabel from './AutoFormLabel.vue' | ||||
| import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/lib/registry/new-york/ui/accordion' | ||||
| import { Button } from '@/lib/registry/new-york/ui/button' | ||||
| import { Separator } from '@/lib/registry/new-york/ui/separator' | ||||
| import { FormItem, FormMessage } from '@/lib/registry/new-york/ui/form' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   fieldName: string | ||||
|   required?: boolean | ||||
|   config?: Config<T> | ||||
|   schema?: z.ZodArray<T> | ||||
|   disabled?: boolean | ||||
| }>() | ||||
|  | ||||
| function isZodArray( | ||||
|   item: z.ZodArray<any> | z.ZodDefault<any>, | ||||
| ): item is z.ZodArray<any> { | ||||
|   return item instanceof z.ZodArray | ||||
| } | ||||
|  | ||||
| function isZodDefault( | ||||
|   item: z.ZodArray<any> | z.ZodDefault<any>, | ||||
| ): item is z.ZodDefault<any> { | ||||
|   return item instanceof z.ZodDefault | ||||
| } | ||||
|  | ||||
| const itemShape = computed(() => { | ||||
|   if (!props.schema) | ||||
|     return | ||||
|  | ||||
|   const schema: z.ZodAny = isZodArray(props.schema) | ||||
|     ? props.schema._def.type | ||||
|     : isZodDefault(props.schema) | ||||
|     // @ts-expect-error missing schema | ||||
|       ? props.schema._def.innerType._def.type | ||||
|       : null | ||||
|  | ||||
|   return { | ||||
|     type: getBaseType(schema), | ||||
|     schema, | ||||
|   } | ||||
| }) | ||||
|  | ||||
| const fieldContext = useField(props.fieldName) | ||||
| // @ts-expect-error ignore missing `id` | ||||
| provide(FieldContextKey, fieldContext) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <FieldArray v-slot="{ fields, remove, push }" as="section" :name="fieldName"> | ||||
|     <slot v-bind="props"> | ||||
|       <Accordion type="multiple" class="w-full" collapsible :disabled="disabled" as-child> | ||||
|         <FormItem> | ||||
|           <AccordionItem :value="fieldName" class="border-none"> | ||||
|             <AccordionTrigger> | ||||
|               <AutoFormLabel class="text-base" :required="required"> | ||||
|                 {{ schema?.description || beautifyObjectName(fieldName) }} | ||||
|               </AutoFormLabel> | ||||
|             </AccordionTrigger> | ||||
|  | ||||
|             <AccordionContent> | ||||
|               <template v-for="(field, index) of fields" :key="field.key"> | ||||
|                 <div class="mb-4 p-1"> | ||||
|                   <AutoFormField | ||||
|                     :field-name="`${fieldName}[${index}]`" | ||||
|                     :label="fieldName" | ||||
|                     :shape="itemShape!" | ||||
|                     :config="config as ConfigItem" | ||||
|                   /> | ||||
|  | ||||
|                   <div class="!my-4 flex justify-end"> | ||||
|                     <Button | ||||
|                       type="button" | ||||
|                       size="icon" | ||||
|                       variant="secondary" | ||||
|                       @click="remove(index)" | ||||
|                     > | ||||
|                       <TrashIcon :size="16" /> | ||||
|                     </Button> | ||||
|                   </div> | ||||
|                   <Separator v-if="!field.isLast" /> | ||||
|                 </div> | ||||
|               </template> | ||||
|  | ||||
|               <Button | ||||
|                 type="button" | ||||
|                 variant="secondary" | ||||
|                 class="mt-4 flex items-center" | ||||
|                 @click="push(null)" | ||||
|               > | ||||
|                 <PlusIcon class="mr-2" :size="16" /> | ||||
|                 Add | ||||
|               </Button> | ||||
|             </AccordionContent> | ||||
|  | ||||
|             <FormMessage /> | ||||
|           </AccordionItem> | ||||
|         </FormItem> | ||||
|       </Accordion> | ||||
|     </slot> | ||||
|   </FieldArray> | ||||
| </template> | ||||
| @@ -0,0 +1,41 @@ | ||||
| <script setup lang="ts"> | ||||
| import { computed } from 'vue' | ||||
| import { beautifyObjectName } from './utils' | ||||
| import type { FieldProps } from './interface' | ||||
| import AutoFormLabel from './AutoFormLabel.vue' | ||||
| import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form' | ||||
| import { Switch } from '@/lib/registry/new-york/ui/switch' | ||||
| import { Checkbox } from '@/lib/registry/new-york/ui/checkbox' | ||||
|  | ||||
| const props = defineProps<FieldProps>() | ||||
|  | ||||
| const booleanComponent = computed(() => props.config?.component === 'switch' ? Switch : Checkbox) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <FormField v-slot="slotProps" :name="fieldName"> | ||||
|     <FormItem> | ||||
|       <div class="space-y-0 mb-3 flex items-center gap-3"> | ||||
|         <FormControl> | ||||
|           <slot v-bind="slotProps"> | ||||
|             <component | ||||
|               :is="booleanComponent" | ||||
|               v-bind="{ ...slotProps.componentField }" | ||||
|               :disabled="disabled" | ||||
|               :checked="slotProps.componentField.modelValue" | ||||
|               @update:checked="slotProps.componentField['onUpdate:modelValue']" | ||||
|             /> | ||||
|           </slot> | ||||
|         </FormControl> | ||||
|         <AutoFormLabel v-if="!config?.hideLabel" :required="required"> | ||||
|           {{ config?.label || beautifyObjectName(label ?? fieldName) }} | ||||
|         </AutoFormLabel> | ||||
|       </div> | ||||
|  | ||||
|       <FormDescription v-if="config?.description"> | ||||
|         {{ config.description }} | ||||
|       </FormDescription> | ||||
|       <FormMessage /> | ||||
|     </FormItem> | ||||
|   </FormField> | ||||
| </template> | ||||
| @@ -0,0 +1,57 @@ | ||||
| <script setup lang="ts"> | ||||
| import { DateFormatter, getLocalTimeZone } from '@internationalized/date' | ||||
| import { CalendarIcon } from '@radix-icons/vue' | ||||
| import { beautifyObjectName } from './utils' | ||||
| import AutoFormLabel from './AutoFormLabel.vue' | ||||
| import type { FieldProps } from './interface' | ||||
| import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form' | ||||
|  | ||||
| import { Calendar } from '@/lib/registry/new-york/ui/calendar' | ||||
| import { Button } from '@/lib/registry/new-york/ui/button' | ||||
| import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| defineProps<FieldProps>() | ||||
|  | ||||
| const df = new DateFormatter('en-US', { | ||||
|   dateStyle: 'long', | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <FormField v-slot="slotProps" :name="fieldName"> | ||||
|     <FormItem> | ||||
|       <AutoFormLabel v-if="!config?.hideLabel" :required="required"> | ||||
|         {{ config?.label || beautifyObjectName(label ?? fieldName) }} | ||||
|       </AutoFormLabel> | ||||
|       <FormControl> | ||||
|         <slot v-bind="slotProps"> | ||||
|           <div> | ||||
|             <Popover> | ||||
|               <PopoverTrigger as-child :disabled="disabled"> | ||||
|                 <Button | ||||
|                   variant="outline" | ||||
|                   :class="cn( | ||||
|                     'w-full justify-start text-left font-normal', | ||||
|                     !slotProps.componentField.modelValue && 'text-muted-foreground', | ||||
|                   )" | ||||
|                 > | ||||
|                   <CalendarIcon class="mr-2 h-4 w-4" /> | ||||
|                   {{ slotProps.componentField.modelValue ? df.format(slotProps.componentField.modelValue.toDate(getLocalTimeZone())) : "Pick a date" }} | ||||
|                 </Button> | ||||
|               </PopoverTrigger> | ||||
|               <PopoverContent class="w-auto p-0"> | ||||
|                 <Calendar initial-focus v-bind="slotProps.componentField" /> | ||||
|               </PopoverContent> | ||||
|             </Popover> | ||||
|           </div> | ||||
|         </slot> | ||||
|       </FormControl> | ||||
|  | ||||
|       <FormDescription v-if="config?.description"> | ||||
|         {{ config.description }} | ||||
|       </FormDescription> | ||||
|       <FormMessage /> | ||||
|     </FormItem> | ||||
|   </FormField> | ||||
| </template> | ||||
| @@ -0,0 +1,49 @@ | ||||
| <script setup lang="ts"> | ||||
| import AutoFormLabel from './AutoFormLabel.vue' | ||||
| import { beautifyObjectName } from './utils' | ||||
| import type { FieldProps } from './interface' | ||||
| import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form' | ||||
| import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/lib/registry/new-york/ui/select' | ||||
| import { Label } from '@/lib/registry/new-york/ui/label' | ||||
| import { RadioGroup, RadioGroupItem } from '@/lib/registry/new-york/ui/radio-group' | ||||
|  | ||||
| defineProps<FieldProps & { | ||||
|   options?: string[] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <FormField v-slot="slotProps" :name="fieldName"> | ||||
|     <FormItem> | ||||
|       <AutoFormLabel v-if="!config?.hideLabel" :required="required"> | ||||
|         {{ config?.label || beautifyObjectName(label ?? fieldName) }} | ||||
|       </AutoFormLabel> | ||||
|       <FormControl> | ||||
|         <slot v-bind="slotProps"> | ||||
|           <RadioGroup v-if="config?.component === 'radio'" :disabled="disabled" :orientation="'vertical'" v-bind="{ ...slotProps.componentField }"> | ||||
|             <div v-for="(option, index) in options" :key="option" class="mb-2 flex items-center gap-3 space-y-0"> | ||||
|               <RadioGroupItem :id="`${option}-${index}`" :value="option" /> | ||||
|               <Label :for="`${option}-${index}`">{{ beautifyObjectName(option) }}</Label> | ||||
|             </div> | ||||
|           </RadioGroup> | ||||
|  | ||||
|           <Select v-else :disabled="disabled" v-bind="{ ...slotProps.componentField }"> | ||||
|             <SelectTrigger class="w-full"> | ||||
|               <SelectValue :placeholder="config?.inputProps?.placeholder" /> | ||||
|             </SelectTrigger> | ||||
|             <SelectContent> | ||||
|               <SelectItem v-for="option in options" :key="option" :value="option"> | ||||
|                 {{ beautifyObjectName(option) }} | ||||
|               </SelectItem> | ||||
|             </SelectContent> | ||||
|           </Select> | ||||
|         </slot> | ||||
|       </FormControl> | ||||
|  | ||||
|       <FormDescription v-if="config?.description"> | ||||
|         {{ config.description }} | ||||
|       </FormDescription> | ||||
|       <FormMessage /> | ||||
|     </FormItem> | ||||
|   </FormField> | ||||
| </template> | ||||
| @@ -0,0 +1,74 @@ | ||||
| <script setup lang="ts"> | ||||
| import { ref } from 'vue' | ||||
| import { TrashIcon } from '@radix-icons/vue' | ||||
| import { beautifyObjectName } from './utils' | ||||
| import type { FieldProps } from './interface' | ||||
| import AutoFormLabel from './AutoFormLabel.vue' | ||||
| import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form' | ||||
| import { Input } from '@/lib/registry/new-york/ui/input' | ||||
| import { Button } from '@/lib/registry/new-york/ui/button' | ||||
|  | ||||
| defineProps<FieldProps>() | ||||
|  | ||||
| const inputFile = ref<File>() | ||||
| async function parseFileAsString(file: File | undefined): Promise<string> { | ||||
|   return new Promise((resolve, reject) => { | ||||
|     if (file) { | ||||
|       const reader = new FileReader() | ||||
|       reader.onloadend = () => { | ||||
|         resolve(reader.result as string) | ||||
|       } | ||||
|       reader.onerror = (err) => { | ||||
|         reject(err) | ||||
|       } | ||||
|       reader.readAsDataURL(file) | ||||
|     } | ||||
|   }) | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <FormField v-slot="slotProps" :name="fieldName"> | ||||
|     <FormItem v-bind="$attrs"> | ||||
|       <AutoFormLabel v-if="!config?.hideLabel" :required="required"> | ||||
|         {{ config?.label || beautifyObjectName(label ?? fieldName) }} | ||||
|       </AutoFormLabel> | ||||
|       <FormControl> | ||||
|         <slot v-bind="slotProps"> | ||||
|           <Input | ||||
|             v-if="!inputFile" | ||||
|             type="file" | ||||
|             v-bind="{ ...config?.inputProps }" | ||||
|             :disabled="disabled" | ||||
|             @change="async (ev: InputEvent) => { | ||||
|               const file = (ev.target as HTMLInputElement).files?.[0] | ||||
|               inputFile = file | ||||
|               const parsed = await parseFileAsString(file) | ||||
|               slotProps.componentField.onInput(parsed) | ||||
|             }" | ||||
|           /> | ||||
|           <div v-else class="flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent pl-3 pr-1 py-1 text-sm shadow-sm transition-colors"> | ||||
|             <p>{{ inputFile?.name }}</p> | ||||
|             <Button | ||||
|               :size="'icon'" | ||||
|               :variant="'ghost'" | ||||
|               class="h-[26px] w-[26px]" | ||||
|               aria-label="Remove file" | ||||
|               type="button" | ||||
|               @click="() => { | ||||
|                 inputFile = undefined | ||||
|                 slotProps.componentField.onInput(undefined) | ||||
|               }" | ||||
|             > | ||||
|               <TrashIcon /> | ||||
|             </Button> | ||||
|           </div> | ||||
|         </slot> | ||||
|       </FormControl> | ||||
|       <FormDescription v-if="config?.description"> | ||||
|         {{ config.description }} | ||||
|       </FormDescription> | ||||
|       <FormMessage /> | ||||
|     </FormItem> | ||||
|   </FormField> | ||||
| </template> | ||||
| @@ -0,0 +1,36 @@ | ||||
| <script setup lang="ts"> | ||||
| import { computed } from 'vue' | ||||
| import AutoFormLabel from './AutoFormLabel.vue' | ||||
| import { beautifyObjectName } from './utils' | ||||
| import type { FieldProps } from './interface' | ||||
| import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form' | ||||
| import { Input } from '@/lib/registry/new-york/ui/input' | ||||
| import { Textarea } from '@/lib/registry/new-york/ui/textarea' | ||||
|  | ||||
| const props = defineProps<FieldProps>() | ||||
| const inputComponent = computed(() => props.config?.component === 'textarea' ? Textarea : Input) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <FormField v-slot="slotProps" :name="fieldName"> | ||||
|     <FormItem v-bind="$attrs"> | ||||
|       <AutoFormLabel v-if="!config?.hideLabel" :required="required"> | ||||
|         {{ config?.label || beautifyObjectName(label ?? fieldName) }} | ||||
|       </AutoFormLabel> | ||||
|       <FormControl> | ||||
|         <slot v-bind="slotProps"> | ||||
|           <component | ||||
|             :is="inputComponent" | ||||
|             type="text" | ||||
|             v-bind="{ ...slotProps.componentField, ...config?.inputProps }" | ||||
|             :disabled="disabled" | ||||
|           /> | ||||
|         </slot> | ||||
|       </FormControl> | ||||
|       <FormDescription v-if="config?.description"> | ||||
|         {{ config.description }} | ||||
|       </FormDescription> | ||||
|       <FormMessage /> | ||||
|     </FormItem> | ||||
|   </FormField> | ||||
| </template> | ||||
| @@ -0,0 +1,32 @@ | ||||
| <script setup lang="ts"> | ||||
| import AutoFormLabel from './AutoFormLabel.vue' | ||||
| import { beautifyObjectName } from './utils' | ||||
| import type { FieldProps } from './interface' | ||||
| import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/lib/registry/new-york/ui/form' | ||||
| import { Input } from '@/lib/registry/new-york/ui/input' | ||||
|  | ||||
| defineOptions({ | ||||
|   inheritAttrs: false, | ||||
| }) | ||||
|  | ||||
| defineProps<FieldProps>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <FormField v-slot="slotProps" :name="fieldName"> | ||||
|     <FormItem> | ||||
|       <AutoFormLabel v-if="!config?.hideLabel" :required="required"> | ||||
|         {{ config?.label || beautifyObjectName(label ?? fieldName) }} | ||||
|       </AutoFormLabel> | ||||
|       <FormControl> | ||||
|         <slot v-bind="slotProps"> | ||||
|           <Input type="number" v-bind="{ ...slotProps.componentField, ...config?.inputProps }" :disabled="disabled" /> | ||||
|         </slot> | ||||
|       </FormControl> | ||||
|       <FormDescription v-if="config?.description"> | ||||
|         {{ config.description }} | ||||
|       </FormDescription> | ||||
|       <FormMessage /> | ||||
|     </FormItem> | ||||
|   </FormField> | ||||
| </template> | ||||
| @@ -0,0 +1,78 @@ | ||||
| <script setup lang="ts" generic="T extends ZodRawShape"> | ||||
| import type { ZodAny, ZodObject, ZodRawShape } from 'zod' | ||||
| import { computed, provide } from 'vue' | ||||
| import { FieldContextKey, useField } from 'vee-validate' | ||||
| import AutoFormField from './AutoFormField.vue' | ||||
| import type { Config, ConfigItem, Shape } from './interface' | ||||
| import { beautifyObjectName, getBaseSchema, getBaseType, getDefaultValueInZodStack } from './utils' | ||||
| import AutoFormLabel from './AutoFormLabel.vue' | ||||
| import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/lib/registry/new-york/ui/accordion' | ||||
| import { FormItem } from '@/lib/registry/new-york/ui/form' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   fieldName: string | ||||
|   required?: boolean | ||||
|   config?: Config<T> | ||||
|   schema?: ZodObject<T> | ||||
|   disabled?: boolean | ||||
| }>() | ||||
|  | ||||
| const shapes = computed(() => { | ||||
|   // @ts-expect-error ignore {} not assignable to object | ||||
|   const val: { [key in keyof T]: Shape } = {} | ||||
|  | ||||
|   if (!props.schema) | ||||
|     return | ||||
|   const shape = getBaseSchema(props.schema)?.shape | ||||
|   if (!shape) | ||||
|     return | ||||
|   Object.keys(shape).forEach((name) => { | ||||
|     const item = shape[name] as ZodAny | ||||
|     const baseItem = getBaseSchema(item) as ZodAny | ||||
|     let options = (baseItem && 'values' in baseItem._def) ? baseItem._def.values as string[] : undefined | ||||
|     if (!Array.isArray(options) && typeof options === 'object') | ||||
|       options = Object.values(options) | ||||
|  | ||||
|     val[name as keyof T] = { | ||||
|       type: getBaseType(item), | ||||
|       default: getDefaultValueInZodStack(item), | ||||
|       options, | ||||
|       required: !['ZodOptional', 'ZodNullable'].includes(item._def.typeName), | ||||
|       schema: item, | ||||
|     } | ||||
|   }) | ||||
|   return val | ||||
| }) | ||||
|  | ||||
| const fieldContext = useField(props.fieldName) | ||||
| // @ts-expect-error ignore missing `id` | ||||
| provide(FieldContextKey, fieldContext) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <section> | ||||
|     <slot v-bind="props"> | ||||
|       <Accordion type="single" as-child class="w-full" collapsible :disabled="disabled"> | ||||
|         <FormItem> | ||||
|           <AccordionItem :value="fieldName" class="border-none"> | ||||
|             <AccordionTrigger> | ||||
|               <AutoFormLabel class="text-base" :required="required"> | ||||
|                 {{ schema?.description || beautifyObjectName(fieldName) }} | ||||
|               </AutoFormLabel> | ||||
|             </AccordionTrigger> | ||||
|             <AccordionContent class="p-1 space-y-5"> | ||||
|               <template v-for="(shape, key) in shapes" :key="key"> | ||||
|                 <AutoFormField | ||||
|                   :config="config?.[key as keyof typeof config] as ConfigItem" | ||||
|                   :field-name="`${fieldName}.${key.toString()}`" | ||||
|                   :label="key.toString()" | ||||
|                   :shape="shape" | ||||
|                 /> | ||||
|               </template> | ||||
|             </AccordionContent> | ||||
|           </AccordionItem> | ||||
|         </FormItem> | ||||
|       </Accordion> | ||||
|     </slot> | ||||
|   </section> | ||||
| </template> | ||||
| @@ -0,0 +1,14 @@ | ||||
| <script setup lang="ts"> | ||||
| import { FormLabel } from '@/lib/registry/new-york/ui/form' | ||||
|  | ||||
| defineProps<{ | ||||
|   required?: boolean | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <FormLabel> | ||||
|     <slot /> | ||||
|     <span v-if="required" class="text-destructive"> *</span> | ||||
|   </FormLabel> | ||||
| </template> | ||||
							
								
								
									
										39
									
								
								desktop/template/src/packages/shadcn/auto-form/constant.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								desktop/template/src/packages/shadcn/auto-form/constant.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| import AutoFormFieldArray from './AutoFormFieldArray.vue' | ||||
| import AutoFormFieldBoolean from './AutoFormFieldBoolean.vue' | ||||
| import AutoFormFieldDate from './AutoFormFieldDate.vue' | ||||
| import AutoFormFieldEnum from './AutoFormFieldEnum.vue' | ||||
| import AutoFormFieldFile from './AutoFormFieldFile.vue' | ||||
| import AutoFormFieldInput from './AutoFormFieldInput.vue' | ||||
| import AutoFormFieldNumber from './AutoFormFieldNumber.vue' | ||||
| import AutoFormFieldObject from './AutoFormFieldObject.vue' | ||||
|  | ||||
| export const INPUT_COMPONENTS = { | ||||
|   date: AutoFormFieldDate, | ||||
|   select: AutoFormFieldEnum, | ||||
|   radio: AutoFormFieldEnum, | ||||
|   checkbox: AutoFormFieldBoolean, | ||||
|   switch: AutoFormFieldBoolean, | ||||
|   textarea: AutoFormFieldInput, | ||||
|   number: AutoFormFieldNumber, | ||||
|   string: AutoFormFieldInput, | ||||
|   file: AutoFormFieldFile, | ||||
|   array: AutoFormFieldArray, | ||||
|   object: AutoFormFieldObject, | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Define handlers for specific Zod types. | ||||
|  * You can expand this object to support more types. | ||||
|  */ | ||||
| export const DEFAULT_ZOD_HANDLERS: { | ||||
|   [key: string]: keyof typeof INPUT_COMPONENTS | ||||
| } = { | ||||
|   ZodString: 'string', | ||||
|   ZodBoolean: 'checkbox', | ||||
|   ZodDate: 'date', | ||||
|   ZodEnum: 'select', | ||||
|   ZodNativeEnum: 'select', | ||||
|   ZodNumber: 'number', | ||||
|   ZodArray: 'array', | ||||
|   ZodObject: 'object', | ||||
| } | ||||
| @@ -0,0 +1,92 @@ | ||||
| import type * as z from 'zod' | ||||
| import type { Ref } from 'vue' | ||||
| import { computed, ref, watch } from 'vue' | ||||
| import { useFieldValue, useFormValues } from 'vee-validate' | ||||
| import { createContext } from 'radix-vue' | ||||
| import { type Dependency, DependencyType, type EnumValues } from './interface' | ||||
| import { getFromPath, getIndexIfArray } from './utils' | ||||
|  | ||||
| export const [injectDependencies, provideDependencies] = createContext<Ref<Dependency<z.infer<z.ZodObject<any>>>[] | undefined>>('AutoFormDependencies') | ||||
|  | ||||
| export default function useDependencies( | ||||
|   fieldName: string, | ||||
| ) { | ||||
|   const form = useFormValues() | ||||
|   // parsed test[0].age => test.age | ||||
|   const currentFieldName = fieldName.replace(/\[\d+\]/g, '') | ||||
|   const currentFieldValue = useFieldValue<any>(fieldName) | ||||
|  | ||||
|   if (!form) | ||||
|     throw new Error('useDependencies should be used within <AutoForm>') | ||||
|  | ||||
|   const dependencies = injectDependencies() | ||||
|   const isDisabled = ref(false) | ||||
|   const isHidden = ref(false) | ||||
|   const isRequired = ref(false) | ||||
|   const overrideOptions = ref<EnumValues | undefined>() | ||||
|  | ||||
|   const currentFieldDependencies = computed(() => dependencies.value?.filter( | ||||
|     dependency => dependency.targetField === currentFieldName, | ||||
|   )) | ||||
|  | ||||
|   function getSourceValue(dep: Dependency<any>) { | ||||
|     const source = dep.sourceField as string | ||||
|     const index = getIndexIfArray(fieldName) ?? -1 | ||||
|     const [sourceLast, ...sourceInitial] = source.split('.').toReversed() | ||||
|     const [_targetLast, ...targetInitial] = (dep.targetField as string).split('.').toReversed() | ||||
|  | ||||
|     if (index >= 0 && sourceInitial.join(',') === targetInitial.join(',')) { | ||||
|       const [_currentLast, ...currentInitial] = fieldName.split('.').toReversed() | ||||
|       return getFromPath(form.value, currentInitial.join('.') + sourceLast) | ||||
|     } | ||||
|  | ||||
|     return getFromPath(form.value, source) | ||||
|   } | ||||
|  | ||||
|   const sourceFieldValues = computed(() => currentFieldDependencies.value?.map(dep => getSourceValue(dep))) | ||||
|  | ||||
|   const resetConditionState = () => { | ||||
|     isDisabled.value = false | ||||
|     isHidden.value = false | ||||
|     isRequired.value = false | ||||
|     overrideOptions.value = undefined | ||||
|   } | ||||
|  | ||||
|   watch([sourceFieldValues, dependencies], () => { | ||||
|     resetConditionState() | ||||
|     currentFieldDependencies.value?.forEach((dep) => { | ||||
|       const sourceValue = getSourceValue(dep) | ||||
|       const conditionMet = dep.when(sourceValue, currentFieldValue.value) | ||||
|  | ||||
|       switch (dep.type) { | ||||
|         case DependencyType.DISABLES: | ||||
|           if (conditionMet) | ||||
|             isDisabled.value = true | ||||
|  | ||||
|           break | ||||
|         case DependencyType.REQUIRES: | ||||
|           if (conditionMet) | ||||
|             isRequired.value = true | ||||
|  | ||||
|           break | ||||
|         case DependencyType.HIDES: | ||||
|           if (conditionMet) | ||||
|             isHidden.value = true | ||||
|  | ||||
|           break | ||||
|         case DependencyType.SETS_OPTIONS: | ||||
|           if (conditionMet) | ||||
|             overrideOptions.value = dep.options | ||||
|  | ||||
|           break | ||||
|       } | ||||
|     }) | ||||
|   }, { immediate: true, deep: true }) | ||||
|  | ||||
|   return { | ||||
|     isDisabled, | ||||
|     isHidden, | ||||
|     isRequired, | ||||
|     overrideOptions, | ||||
|   } | ||||
| } | ||||
							
								
								
									
										15
									
								
								desktop/template/src/packages/shadcn/auto-form/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								desktop/template/src/packages/shadcn/auto-form/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| export { getObjectFormSchema, getBaseSchema, getBaseType } from './utils' | ||||
| export type { Config, ConfigItem, FieldProps } from './interface' | ||||
|  | ||||
| export { default as AutoForm } from './AutoForm.vue' | ||||
| export { default as AutoFormField } from './AutoFormField.vue' | ||||
| export { default as AutoFormLabel } from './AutoFormLabel.vue' | ||||
|  | ||||
| export { default as AutoFormFieldArray } from './AutoFormFieldArray.vue' | ||||
| export { default as AutoFormFieldBoolean } from './AutoFormFieldBoolean.vue' | ||||
| export { default as AutoFormFieldDate } from './AutoFormFieldDate.vue' | ||||
| export { default as AutoFormFieldEnum } from './AutoFormFieldEnum.vue' | ||||
| export { default as AutoFormFieldFile } from './AutoFormFieldFile.vue' | ||||
| export { default as AutoFormFieldInput } from './AutoFormFieldInput.vue' | ||||
| export { default as AutoFormFieldNumber } from './AutoFormFieldNumber.vue' | ||||
| export { default as AutoFormFieldObject } from './AutoFormFieldObject.vue' | ||||
							
								
								
									
										81
									
								
								desktop/template/src/packages/shadcn/auto-form/interface.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								desktop/template/src/packages/shadcn/auto-form/interface.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| import type { Component, InputHTMLAttributes } from 'vue' | ||||
| import type { ZodAny, z } from 'zod' | ||||
| import type { INPUT_COMPONENTS } from './constant' | ||||
|  | ||||
| export interface FieldProps { | ||||
|   fieldName: string | ||||
|   label?: string | ||||
|   required?: boolean | ||||
|   config?: ConfigItem | ||||
|   disabled?: boolean | ||||
| } | ||||
|  | ||||
| export interface Shape { | ||||
|   type: string | ||||
|   default?: any | ||||
|   required?: boolean | ||||
|   options?: string[] | ||||
|   schema?: ZodAny | ||||
| } | ||||
|  | ||||
| export interface ConfigItem { | ||||
|   /** Value for the `FormLabel` */ | ||||
|   label?: string | ||||
|   /** Value for the `FormDescription` */ | ||||
|   description?: string | ||||
|   /** Pick which component to be rendered. */ | ||||
|   component?: keyof typeof INPUT_COMPONENTS | Component | ||||
|   /** Hide `FormLabel`. */ | ||||
|   hideLabel?: boolean | ||||
|   inputProps?: InputHTMLAttributes | ||||
| } | ||||
|  | ||||
| // Define a type to unwrap an array | ||||
| type UnwrapArray<T> = T extends (infer U)[] ? U : never | ||||
|  | ||||
| export type Config<SchemaType extends object> = { | ||||
|   // If SchemaType.key is an object, create a nested Config, otherwise ConfigItem | ||||
|   [Key in keyof SchemaType]?: | ||||
|   SchemaType[Key] extends any[] | ||||
|     ? UnwrapArray<Config<SchemaType[Key]>> | ||||
|     : SchemaType[Key] extends object | ||||
|       ? Config<SchemaType[Key]> | ||||
|       : ConfigItem; | ||||
| } | ||||
|  | ||||
| export enum DependencyType { | ||||
|   DISABLES, | ||||
|   REQUIRES, | ||||
|   HIDES, | ||||
|   SETS_OPTIONS, | ||||
| } | ||||
|  | ||||
| interface BaseDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> { | ||||
|   sourceField: keyof SchemaType | ||||
|   type: DependencyType | ||||
|   targetField: keyof SchemaType | ||||
|   when: (sourceFieldValue: any, targetFieldValue: any) => boolean | ||||
| } | ||||
|  | ||||
| export type ValueDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> = | ||||
|   BaseDependency<SchemaType> & { | ||||
|     type: | ||||
|       | DependencyType.DISABLES | ||||
|       | DependencyType.REQUIRES | ||||
|       | DependencyType.HIDES | ||||
|   } | ||||
|  | ||||
| export type EnumValues = readonly [string, ...string[]] | ||||
|  | ||||
| export type OptionsDependency< | ||||
|   SchemaType extends z.infer<z.ZodObject<any, any>>, | ||||
| > = BaseDependency<SchemaType> & { | ||||
|   type: DependencyType.SETS_OPTIONS | ||||
|  | ||||
|   // Partial array of values from sourceField that will trigger the dependency | ||||
|   options: EnumValues | ||||
| } | ||||
|  | ||||
| export type Dependency<SchemaType extends z.infer<z.ZodObject<any, any>>> = | ||||
|   | ValueDependency<SchemaType> | ||||
|   | OptionsDependency<SchemaType> | ||||
							
								
								
									
										171
									
								
								desktop/template/src/packages/shadcn/auto-form/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								desktop/template/src/packages/shadcn/auto-form/utils.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| import type { z } from 'zod' | ||||
|  | ||||
| // TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions. | ||||
| export type ZodObjectOrWrapped = | ||||
|   | z.ZodObject<any, any> | ||||
|   | z.ZodEffects<z.ZodObject<any, any>> | ||||
|  | ||||
| /** | ||||
|  * Beautify a camelCase string. | ||||
|  * e.g. "myString" -> "My String" | ||||
|  */ | ||||
| export function beautifyObjectName(string: string) { | ||||
|   // Remove bracketed indices | ||||
|   // if numbers only return the string | ||||
|   let output = string.replace(/\[\d+\]/g, '').replace(/([A-Z])/g, ' $1') | ||||
|   output = output.charAt(0).toUpperCase() + output.slice(1) | ||||
|   return output | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Parse string and extract the index | ||||
|  * @param string | ||||
|  * @returns index or undefined | ||||
|  */ | ||||
| export function getIndexIfArray(string: string) { | ||||
|   const indexRegex = /\[(\d+)\]/ | ||||
|   // Match the index | ||||
|   const match = string.match(indexRegex) | ||||
|   // Extract the index (number) | ||||
|   const index = match ? Number.parseInt(match[1]) : undefined | ||||
|   return index | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Get the lowest level Zod type. | ||||
|  * This will unpack optionals, refinements, etc. | ||||
|  */ | ||||
| export function getBaseSchema< | ||||
|   ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny, | ||||
| >(schema: ChildType | z.ZodEffects<ChildType>): ChildType | null { | ||||
|   if (!schema) | ||||
|     return null | ||||
|   if ('innerType' in schema._def) | ||||
|     return getBaseSchema(schema._def.innerType as ChildType) | ||||
|  | ||||
|   if ('schema' in schema._def) | ||||
|     return getBaseSchema(schema._def.schema as ChildType) | ||||
|  | ||||
|   return schema as ChildType | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Get the type name of the lowest level Zod type. | ||||
|  * This will unpack optionals, refinements, etc. | ||||
|  */ | ||||
| export function getBaseType(schema: z.ZodAny) { | ||||
|   const baseSchema = getBaseSchema(schema) | ||||
|   return baseSchema ? baseSchema._def.typeName : '' | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Search for a "ZodDefault" in the Zod stack and return its value. | ||||
|  */ | ||||
| export function getDefaultValueInZodStack(schema: z.ZodAny): any { | ||||
|   const typedSchema = schema as unknown as z.ZodDefault< | ||||
|     z.ZodNumber | z.ZodString | ||||
|   > | ||||
|  | ||||
|   if (typedSchema._def.typeName === 'ZodDefault') | ||||
|     return typedSchema._def.defaultValue() | ||||
|  | ||||
|   if ('innerType' in typedSchema._def) { | ||||
|     return getDefaultValueInZodStack( | ||||
|       typedSchema._def.innerType as unknown as z.ZodAny, | ||||
|     ) | ||||
|   } | ||||
|   if ('schema' in typedSchema._def) { | ||||
|     return getDefaultValueInZodStack( | ||||
|       (typedSchema._def as any).schema as z.ZodAny, | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   return undefined | ||||
| } | ||||
|  | ||||
| export function getObjectFormSchema( | ||||
|   schema: ZodObjectOrWrapped, | ||||
| ): z.ZodObject<any, any> { | ||||
|   if (schema?._def.typeName === 'ZodEffects') { | ||||
|     const typedSchema = schema as z.ZodEffects<z.ZodObject<any, any>> | ||||
|     return getObjectFormSchema(typedSchema._def.schema) | ||||
|   } | ||||
|   return schema as z.ZodObject<any, any> | ||||
| } | ||||
|  | ||||
| function isIndex(value: unknown): value is number { | ||||
|   return Number(value) >= 0 | ||||
| } | ||||
| /** | ||||
|  * Constructs a path with dot paths for arrays to use brackets to be compatible with vee-validate path syntax | ||||
|  */ | ||||
| export function normalizeFormPath(path: string): string { | ||||
|   const pathArr = path.split('.') | ||||
|   if (!pathArr.length) | ||||
|     return '' | ||||
|  | ||||
|   let fullPath = String(pathArr[0]) | ||||
|   for (let i = 1; i < pathArr.length; i++) { | ||||
|     if (isIndex(pathArr[i])) { | ||||
|       fullPath += `[${pathArr[i]}]` | ||||
|       continue | ||||
|     } | ||||
|  | ||||
|     fullPath += `.${pathArr[i]}` | ||||
|   } | ||||
|  | ||||
|   return fullPath | ||||
| } | ||||
|  | ||||
| type NestedRecord = Record<string, unknown> | { [k: string]: NestedRecord } | ||||
| /** | ||||
|  * Checks if the path opted out of nested fields using `[fieldName]` syntax | ||||
|  */ | ||||
| export function isNotNestedPath(path: string) { | ||||
|   return /^\[.+\]$/i.test(path) | ||||
| } | ||||
| function isObject(obj: unknown): obj is Record<string, unknown> { | ||||
|   return obj !== null && !!obj && typeof obj === 'object' && !Array.isArray(obj) | ||||
| } | ||||
| function isContainerValue(value: unknown): value is Record<string, unknown> { | ||||
|   return isObject(value) || Array.isArray(value) | ||||
| } | ||||
| function cleanupNonNestedPath(path: string) { | ||||
|   if (isNotNestedPath(path)) | ||||
|     return path.replace(/\[|\]/gi, '') | ||||
|  | ||||
|   return path | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Gets a nested property value from an object | ||||
|  */ | ||||
| export function getFromPath<TValue = unknown>(object: NestedRecord | undefined, path: string): TValue | undefined | ||||
| export function getFromPath<TValue = unknown, TFallback = TValue>( | ||||
|   object: NestedRecord | undefined, | ||||
|   path: string, | ||||
|   fallback?: TFallback, | ||||
| ): TValue | TFallback | ||||
| export function getFromPath<TValue = unknown, TFallback = TValue>( | ||||
|   object: NestedRecord | undefined, | ||||
|   path: string, | ||||
|   fallback?: TFallback, | ||||
| ): TValue | TFallback | undefined { | ||||
|   if (!object) | ||||
|     return fallback | ||||
|  | ||||
|   if (isNotNestedPath(path)) | ||||
|     return object[cleanupNonNestedPath(path)] as TValue | undefined | ||||
|  | ||||
|   const resolvedValue = (path || '') | ||||
|     .split(/\.|\[(\d+)\]/) | ||||
|     .filter(Boolean) | ||||
|     .reduce((acc, propKey) => { | ||||
|       if (isContainerValue(acc) && propKey in acc) | ||||
|         return acc[propKey] | ||||
|  | ||||
|       return fallback | ||||
|     }, object as unknown) | ||||
|  | ||||
|   return resolvedValue as TValue | undefined | ||||
| } | ||||
							
								
								
									
										21
									
								
								desktop/template/src/packages/shadcn/avatar/Avatar.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								desktop/template/src/packages/shadcn/avatar/Avatar.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <script setup lang="ts"> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { AvatarRoot } from 'radix-vue' | ||||
| import { type AvatarVariants, avatarVariant } from '.' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
|   size?: AvatarVariants['size'] | ||||
|   shape?: AvatarVariants['shape'] | ||||
| }>(), { | ||||
|   size: 'sm', | ||||
|   shape: 'circle', | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AvatarRoot :class="cn(avatarVariant({ size, shape }), props.class)"> | ||||
|     <slot /> | ||||
|   </AvatarRoot> | ||||
| </template> | ||||
| @@ -0,0 +1,11 @@ | ||||
| <script setup lang="ts"> | ||||
| import { AvatarFallback, type AvatarFallbackProps } from 'radix-vue' | ||||
|  | ||||
| const props = defineProps<AvatarFallbackProps>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AvatarFallback v-bind="props"> | ||||
|     <slot /> | ||||
|   </AvatarFallback> | ||||
| </template> | ||||
| @@ -0,0 +1,9 @@ | ||||
| <script setup lang="ts"> | ||||
| import { AvatarImage, type AvatarImageProps } from 'radix-vue' | ||||
|  | ||||
| const props = defineProps<AvatarImageProps>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <AvatarImage v-bind="props" class="h-full w-full object-cover" /> | ||||
| </template> | ||||
							
								
								
									
										24
									
								
								desktop/template/src/packages/shadcn/avatar/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								desktop/template/src/packages/shadcn/avatar/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| import { type VariantProps, cva } from 'class-variance-authority' | ||||
|  | ||||
| export { default as Avatar } from './Avatar.vue' | ||||
| export { default as AvatarImage } from './AvatarImage.vue' | ||||
| export { default as AvatarFallback } from './AvatarFallback.vue' | ||||
|  | ||||
| export const avatarVariant = cva( | ||||
|   'inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden', | ||||
|   { | ||||
|     variants: { | ||||
|       size: { | ||||
|         sm: 'h-10 w-10 text-xs', | ||||
|         base: 'h-16 w-16 text-2xl', | ||||
|         lg: 'h-32 w-32 text-5xl', | ||||
|       }, | ||||
|       shape: { | ||||
|         circle: 'rounded-full', | ||||
|         square: 'rounded-md', | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
| ) | ||||
|  | ||||
| export type AvatarVariants = VariantProps<typeof avatarVariant> | ||||
							
								
								
									
										16
									
								
								desktop/template/src/packages/shadcn/badge/Badge.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								desktop/template/src/packages/shadcn/badge/Badge.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <script setup lang="ts"> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { type BadgeVariants, badgeVariants } from '.' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   variant?: BadgeVariants['variant'] | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div :class="cn(badgeVariants({ variant }), props.class)"> | ||||
|     <slot /> | ||||
|   </div> | ||||
| </template> | ||||
							
								
								
									
										25
									
								
								desktop/template/src/packages/shadcn/badge/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								desktop/template/src/packages/shadcn/badge/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| import { type VariantProps, cva } from 'class-variance-authority' | ||||
|  | ||||
| export { default as Badge } from './Badge.vue' | ||||
|  | ||||
| export const badgeVariants = cva( | ||||
|   'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', | ||||
|   { | ||||
|     variants: { | ||||
|       variant: { | ||||
|         default: | ||||
|           'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80', | ||||
|         secondary: | ||||
|           'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', | ||||
|         destructive: | ||||
|           'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80', | ||||
|         outline: 'text-foreground', | ||||
|       }, | ||||
|     }, | ||||
|     defaultVariants: { | ||||
|       variant: 'default', | ||||
|     }, | ||||
|   }, | ||||
| ) | ||||
|  | ||||
| export type BadgeVariants = VariantProps<typeof badgeVariants> | ||||
| @@ -0,0 +1,13 @@ | ||||
| <script lang="ts" setup> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <nav aria-label="breadcrumb" :class="props.class"> | ||||
|     <slot /> | ||||
|   </nav> | ||||
| </template> | ||||
| @@ -0,0 +1,22 @@ | ||||
| <script lang="ts" setup> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { DotsHorizontalIcon } from '@radix-icons/vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <span | ||||
|     role="presentation" | ||||
|     aria-hidden="true" | ||||
|     :class="cn('flex h-9 w-9 items-center justify-center', props.class)" | ||||
|   > | ||||
|     <slot> | ||||
|       <DotsHorizontalIcon class="h-4 w-4" /> | ||||
|     </slot> | ||||
|     <span class="sr-only">More</span> | ||||
|   </span> | ||||
| </template> | ||||
| @@ -0,0 +1,16 @@ | ||||
| <script lang="ts" setup> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <li | ||||
|     :class="cn('inline-flex items-center gap-1.5', props.class)" | ||||
|   > | ||||
|     <slot /> | ||||
|   </li> | ||||
| </template> | ||||
| @@ -0,0 +1,19 @@ | ||||
| <script lang="ts" setup> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { Primitive, type PrimitiveProps } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = withDefaults(defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>(), { | ||||
|   as: 'a', | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <Primitive | ||||
|     :as="as" | ||||
|     :as-child="asChild" | ||||
|     :class="cn('transition-colors hover:text-foreground', props.class)" | ||||
|   > | ||||
|     <slot /> | ||||
|   </Primitive> | ||||
| </template> | ||||
| @@ -0,0 +1,16 @@ | ||||
| <script lang="ts" setup> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ol | ||||
|     :class="cn('flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5', props.class)" | ||||
|   > | ||||
|     <slot /> | ||||
|   </ol> | ||||
| </template> | ||||
| @@ -0,0 +1,19 @@ | ||||
| <script lang="ts" setup> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <span | ||||
|     role="link" | ||||
|     aria-disabled="true" | ||||
|     aria-current="page" | ||||
|     :class="cn('font-normal text-foreground', props.class)" | ||||
|   > | ||||
|     <slot /> | ||||
|   </span> | ||||
| </template> | ||||
| @@ -0,0 +1,21 @@ | ||||
| <script lang="ts" setup> | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { ChevronRightIcon } from '@radix-icons/vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   class?: HTMLAttributes['class'] | ||||
| }>() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <li | ||||
|     role="presentation" | ||||
|     aria-hidden="true" | ||||
|     :class="cn('[&>svg]:size-3.5', props.class)" | ||||
|   > | ||||
|     <slot> | ||||
|       <ChevronRightIcon /> | ||||
|     </slot> | ||||
|   </li> | ||||
| </template> | ||||
							
								
								
									
										7
									
								
								desktop/template/src/packages/shadcn/breadcrumb/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								desktop/template/src/packages/shadcn/breadcrumb/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| export { default as Breadcrumb } from './Breadcrumb.vue' | ||||
| export { default as BreadcrumbEllipsis } from './BreadcrumbEllipsis.vue' | ||||
| export { default as BreadcrumbItem } from './BreadcrumbItem.vue' | ||||
| export { default as BreadcrumbLink } from './BreadcrumbLink.vue' | ||||
| export { default as BreadcrumbList } from './BreadcrumbList.vue' | ||||
| export { default as BreadcrumbPage } from './BreadcrumbPage.vue' | ||||
| export { default as BreadcrumbSeparator } from './BreadcrumbSeparator.vue' | ||||
| @@ -2,7 +2,7 @@ | ||||
| import type { HTMLAttributes } from 'vue' | ||||
| import { Primitive, type PrimitiveProps } from 'radix-vue' | ||||
| import { type ButtonVariants, buttonVariants } from '.' | ||||
| import { cn } from '@/package/lib/utils' | ||||
| import { cn } from '@/lib/utils' | ||||
| 
 | ||||
| interface Props extends PrimitiveProps { | ||||
|   variant?: ButtonVariants['variant'] | ||||
							
								
								
									
										35
									
								
								desktop/template/src/packages/shadcn/button/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								desktop/template/src/packages/shadcn/button/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import { type VariantProps, cva } from 'class-variance-authority' | ||||
|  | ||||
| export { default as Button } from './Button.vue' | ||||
|  | ||||
| export const buttonVariants = cva( | ||||
|   'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', | ||||
|   { | ||||
|     variants: { | ||||
|       variant: { | ||||
|         default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90', | ||||
|         destructive: | ||||
|           'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90', | ||||
|         outline: | ||||
|           'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground', | ||||
|         secondary: | ||||
|           'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80', | ||||
|         ghost: 'hover:bg-accent hover:text-accent-foreground', | ||||
|         link: 'text-primary underline-offset-4 hover:underline', | ||||
|       }, | ||||
|       size: { | ||||
|         default: 'h-9 px-4 py-2', | ||||
|         xs: 'h-7 rounded px-2', | ||||
|         sm: 'h-8 rounded-md px-3 text-xs', | ||||
|         lg: 'h-10 rounded-md px-8', | ||||
|         icon: 'h-9 w-9', | ||||
|       }, | ||||
|     }, | ||||
|     defaultVariants: { | ||||
|       variant: 'default', | ||||
|       size: 'default', | ||||
|     }, | ||||
|   }, | ||||
| ) | ||||
|  | ||||
| export type ButtonVariants = VariantProps<typeof buttonVariants> | ||||
							
								
								
									
										60
									
								
								desktop/template/src/packages/shadcn/calendar/Calendar.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								desktop/template/src/packages/shadcn/calendar/Calendar.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| <script lang="ts" setup> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { CalendarRoot, type CalendarRootEmits, type CalendarRootProps, useForwardPropsEmits } from 'radix-vue' | ||||
| import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNextButton, CalendarPrevButton } from '.' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<CalendarRootProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const emits = defineEmits<CalendarRootEmits>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
|  | ||||
| const forwarded = useForwardPropsEmits(delegatedProps, emits) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <CalendarRoot | ||||
|     v-slot="{ grid, weekDays }" | ||||
|     :class="cn('p-3', props.class)" | ||||
|     v-bind="forwarded" | ||||
|   > | ||||
|     <CalendarHeader> | ||||
|       <CalendarPrevButton /> | ||||
|       <CalendarHeading /> | ||||
|       <CalendarNextButton /> | ||||
|     </CalendarHeader> | ||||
|  | ||||
|     <div class="flex flex-col gap-y-4 mt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0"> | ||||
|       <CalendarGrid v-for="month in grid" :key="month.value.toString()"> | ||||
|         <CalendarGridHead> | ||||
|           <CalendarGridRow> | ||||
|             <CalendarHeadCell | ||||
|               v-for="day in weekDays" :key="day" | ||||
|             > | ||||
|               {{ day }} | ||||
|             </CalendarHeadCell> | ||||
|           </CalendarGridRow> | ||||
|         </CalendarGridHead> | ||||
|         <CalendarGridBody> | ||||
|           <CalendarGridRow v-for="(weekDates, index) in month.rows" :key="`weekDate-${index}`" class="mt-2 w-full"> | ||||
|             <CalendarCell | ||||
|               v-for="weekDate in weekDates" | ||||
|               :key="weekDate.toString()" | ||||
|               :date="weekDate" | ||||
|             > | ||||
|               <CalendarCellTrigger | ||||
|                 :day="weekDate" | ||||
|                 :month="month.value" | ||||
|               /> | ||||
|             </CalendarCell> | ||||
|           </CalendarGridRow> | ||||
|         </CalendarGridBody> | ||||
|       </CalendarGrid> | ||||
|     </div> | ||||
|   </CalendarRoot> | ||||
| </template> | ||||
| @@ -0,0 +1,24 @@ | ||||
| <script lang="ts" setup> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { CalendarCell, type CalendarCellProps, useForwardProps } from 'radix-vue' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<CalendarCellProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
|  | ||||
| const forwardedProps = useForwardProps(delegatedProps) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <CalendarCell | ||||
|     :class="cn('relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:rounded-md [&:has([data-selected])]:bg-accent [&:has([data-selected][data-outside-month])]:bg-accent/50', props.class)" | ||||
|     v-bind="forwardedProps" | ||||
|   > | ||||
|     <slot /> | ||||
|   </CalendarCell> | ||||
| </template> | ||||
| @@ -0,0 +1,38 @@ | ||||
| <script lang="ts" setup> | ||||
| import { type HTMLAttributes, computed } from 'vue' | ||||
| import { CalendarCellTrigger, type CalendarCellTriggerProps, useForwardProps } from 'radix-vue' | ||||
| import { buttonVariants } from '@/lib/registry/default/ui/button' | ||||
| import { cn } from '@/lib/utils' | ||||
|  | ||||
| const props = defineProps<CalendarCellTriggerProps & { class?: HTMLAttributes['class'] }>() | ||||
|  | ||||
| const delegatedProps = computed(() => { | ||||
|   const { class: _, ...delegated } = props | ||||
|  | ||||
|   return delegated | ||||
| }) | ||||
|  | ||||
| const forwardedProps = useForwardProps(delegatedProps) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <CalendarCellTrigger | ||||
|     :class="cn( | ||||
|       buttonVariants({ variant: 'ghost' }), | ||||
|       'h-8 w-8 p-0 font-normal', | ||||
|       '[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground', | ||||
|       // Selected | ||||
|       'data-[selected]:bg-primary data-[selected]:text-primary-foreground data-[selected]:opacity-100 data-[selected]:hover:bg-primary data-[selected]:hover:text-primary-foreground data-[selected]:focus:bg-primary data-[selected]:focus:text-primary-foreground', | ||||
|       // Disabled | ||||
|       'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50', | ||||
|       // Unavailable | ||||
|       'data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through', | ||||
|       // Outside months | ||||
|       'data-[outside-month]:pointer-events-none data-[outside-month]:text-muted-foreground data-[outside-month]:opacity-50 [&[data-outside-month][data-selected]]:bg-accent/50 [&[data-outside-month][data-selected]]:text-muted-foreground [&[data-outside-month][data-selected]]:opacity-30', | ||||
|       props.class, | ||||
|     )" | ||||
|     v-bind="forwardedProps" | ||||
|   > | ||||
|     <slot /> | ||||
|   </CalendarCellTrigger> | ||||
| </template> | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user