A simple example demonstrating LiveTemplate's file upload feature with avatar upload functionality.
func (s *ProfileStore) AllowUploads() map[string]livetemplate.UploadConfig {
return map[string]livetemplate.UploadConfig{
"avatar": {
Accept: []string{"image/jpeg", "image/png", "image/gif"},
MaxFileSize: 5 * 1024 * 1024, // 5MB
MaxEntries: 1, // Single file
AutoUpload: false, // Manual upload on form submit
ChunkSize: 256 * 1024, // 256KB chunks
},
}
}
func (s *ProfileStore) ConsumeUpload(ctx context.Context, name string, entries []*livetemplate.UploadEntry) error {
for _, entry := range entries {
// Move from temp to permanent location
permanentPath := filepath.Join("uploads", fmt.Sprintf("avatar-%s%s", entry.ID, ext))
os.Rename(entry.TempPath, permanentPath)
// Update store with new avatar
s.AvatarPath = permanentPath
s.AvatarURL = "/" + permanentPath
}
return nil
}
<input type="file" lvt-upload="avatar" accept="image/jpeg,image/png,image/gif">
<!-- Show upload progress -->
{{range .lvt.Uploads "avatar"}}
<div class="upload-entry">
<span>{{.ClientName}} - {{.Progress}}%</span>
<progress value="{{.Progress}}" max="100"></progress>
{{if .Error}}<span class="error">{{.Error}}</span>{{end}}
</div>
{{end}}
cd /Users/adnaan/code/livetemplate/examples/avatar-upload
go mod download
go run main.go
The server will start at http://localhost:8080
This example uses WebSocket Chunked Upload:
avatar-upload/
├── main.go # Server code with ProfileStore
├── avatar-upload.tmpl # HTML template with upload UI
├── go.mod # Dependencies (uses local livetemplate)
├── README.md # This file
└── uploads/ # Created at runtime for uploaded avatars
This example demonstrates:
Want to extend this example?
MaxEntries to allow multiple imagesAutoUpload: true for instant uploadsUpload not working?
Progress not updating?
Files not saving?
uploads/ directory exists (created automatically)Built with ❤️ using LiveTemplate v0.3.0