1package moodstone23import (4 "chain/runtime"5 "chain/runtime/unsafe"6 "strconv"7 "strings"8)910// Entry holds a single mood log.11type Entry struct {12 Author address13 Mood string14 Note string15 Block int6416}1718var entries []Entry1920var validMoods = []string{"happy", "sad", "excited", "calm", "anxious", "angry", "neutral"}2122func isValid(mood string) bool {23 for _, m := range validMoods {24 if m == mood {25 return true26 }27 }28 return false29}3031func emoji(mood string) string {32 switch mood {33 case "happy":34 return "😊"35 case "sad":36 return "😢"37 case "excited":38 return "🎉"39 case "calm":40 return "😌"41 case "anxious":42 return "😰"43 case "angry":44 return "😠"45 case "neutral":46 return "😐"47 }48 return "❓"49}5051func shortAddr(addr address) string {52 s := addr.String()53 if len(s) <= 12 {54 return s55 }56 return s[:6] + "…" + s[len(s)-4:]57}5859func bar(count, total int) string {60 if total == 0 {61 return strings.Repeat("░", 20)62 }63 filled := (count * 20) / total64 return strings.Repeat("▓", filled) + strings.Repeat("░", 20-filled)65}6667// LogMood records the caller's current mood with an optional note.68// mood must be one of: happy sad excited calm anxious angry neutral69func LogMood(_ realm, mood, note string) {70 mood = strings.ToLower(strings.TrimSpace(mood))71 if !isValid(mood) {72 panic("invalid mood; choose from: " + strings.Join(validMoods, ", "))73 }74 entries = append(entries, Entry{75 Author: unsafe.OriginCaller(),76 Mood: mood,77 Note: strings.TrimSpace(note),78 Block: runtime.ChainHeight(),79 })80}8182// TotalEntries returns the total number of mood logs on record.83func TotalEntries() int {84 return len(entries)85}8687// MoodCount returns how many times the given mood has been logged.88func MoodCount(mood string) int {89 mood = strings.ToLower(strings.TrimSpace(mood))90 n := 091 for _, e := range entries {92 if e.Mood == mood {93 n++94 }95 }96 return n97}9899// DominantMood returns the most-logged mood, or "none" if no entries.100func DominantMood() string {101 if len(entries) == 0 {102 return "none"103 }104 counts := make(map[string]int)105 for _, e := range entries {106 counts[e.Mood]++107 }108 best := ""109 bestN := 0110 for _, m := range validMoods {111 if counts[m] > bestN {112 bestN = counts[m]113 best = m114 }115 }116 return best117}118119func Render(path string) string {120 out := "# 🪨 Moodstone — On-chain Mood Tracker\n\n"121 out += "> Log how you feel. Watch how the community feels. Immutably, on Gno.\n\n"122123 total := len(entries)124125 // Community stats table126 out += "## 📊 Community Vibes\n\n"127 if total == 0 {128 out += "*No moods logged yet — be the first!*\n\n"129 } else {130 counts := make(map[string]int)131 for _, e := range entries {132 counts[e.Mood]++133 }134 out += "| Mood | Count | Distribution |\n"135 out += "|------|-------|--------------|\n"136 for _, m := range validMoods {137 c := counts[m]138 pct := 0139 if total > 0 {140 pct = (c * 100) / total141 }142 out += "| " + emoji(m) + " " + m + " | " + strconv.Itoa(c) +143 " | `" + bar(c, total) + "` " + strconv.Itoa(pct) + "% |\n"144 }145 dom := DominantMood()146 out += "\n**Total entries:** " + strconv.Itoa(total) +147 " · **Dominant mood:** " + emoji(dom) + " " + dom + "\n\n"148 }149150 // Recent entries (newest first, max 10)151 out += "## 📝 Recent Entries\n\n"152 if total == 0 {153 out += "*Nothing here yet.*\n\n"154 } else {155 start := total - 10156 if start < 0 {157 start = 0158 }159 for i := total - 1; i >= start; i-- {160 e := entries[i]161 line := "- " + emoji(e.Mood) + " **" + e.Mood + "**"162 if e.Note != "" {163 line += ": *" + e.Note + "*"164 }165 line += " — `" + shortAddr(e.Author) + "` at block " +166 strconv.FormatInt(e.Block, 10)167 out += line + "\n"168 }169 out += "\n"170 }171172 // How to use173 out += "## 🚀 How to Use\n\n"174 out += "```bash\n"175 out += "gnokey maketx call \\\n"176 out += " -pkgpath gno.land/r/g12cs4cehujpffpjpywmkqj43m6u5ya53nj69sjz/moodstone \\\n"177 out += " -func LogMood \\\n"178 out += " -args 'happy' -args 'Just shipped something awesome!'\n"179 out += "```\n\n"180 out += "**Valid moods:** " + strings.Join(validMoods, " · ") + "\n"181182 return out183}184DominantMood() string
LogMood(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, mood string, note string)
MoodCount(mood string) int
Render(path string) string
TotalEntries() int
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.