Commit c9009a549fa3a201c4d0e6c5ca17dec64270260a

Authored by yibo
1 parent c9834ccb

Move nickname UI above the chat input, trigger on input focus

- "昵称 X ✎" button (next to the "聊天" title) replaced with a row directly
  above the chat input: hidden until a nickname is set, then shows
  "<nickname>  change name" — matches infiniteslop.ai's own placement/label
- Nickname prompt now triggers on focusing the chat input itself, not just
  on hitting send — so a first-time visitor sees it the moment they click in

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
library.json
1 [ 1 [
2 { 2 {
  3 + "id": "8024972d6019",
  4 + "source": "h3console",
  5 + "prompt": "蛤蟆文太跳出来了打架",
  6 + "fullPrompt": "蛤蟆文太跳出来了打架",
  7 + "edited": false,
  8 + "width": 832,
  9 + "height": 480,
  10 + "duration": 5,
  11 + "partition": "text",
  12 + "likes": 0,
  13 + "createdAt": 1788249485816
  14 + },
  15 + {
3 "id": "0ade3648412f", 16 "id": "0ade3648412f",
4 "source": "h3console", 17 "source": "h3console",
5 "prompt": "来一只猫在草地上玩耍", 18 "prompt": "来一只猫在草地上玩耍",
@@ -53,7 +66,7 @@ @@ -53,7 +66,7 @@
53 "likes": 0, 66 "likes": 0,
54 "createdAt": 1788192915845, 67 "createdAt": 1788192915845,
55 "promptEn": "scholar watches the room warily", 68 "promptEn": "scholar watches the room warily",
56 - "lastPlayedAt": 1788246004885 69 + "lastPlayedAt": 1788249895446
57 }, 70 },
58 { 71 {
59 "id": "e8cbb73560ef", 72 "id": "e8cbb73560ef",
@@ -307,7 +320,7 @@ @@ -307,7 +320,7 @@
307 "partition": "ref2va", 320 "partition": "ref2va",
308 "likes": 0, 321 "likes": 0,
309 "createdAt": 1788187365789, 322 "createdAt": 1788187365789,
310 - "lastPlayedAt": 1788247402036, 323 + "lastPlayedAt": 1788249805778,
311 "promptEn": "woman in white being gentle and comforting" 324 "promptEn": "woman in white being gentle and comforting"
312 }, 325 },
313 { 326 {
@@ -488,7 +501,7 @@ @@ -488,7 +501,7 @@
488 "likes": 0, 501 "likes": 0,
489 "createdAt": 1788138492364, 502 "createdAt": 1788138492364,
490 "promptEn": "astronaut on a Martian canyon, helmet reflecting an alien ruined city", 503 "promptEn": "astronaut on a Martian canyon, helmet reflecting an alien ruined city",
491 - "lastPlayedAt": 1788247866434 504 + "lastPlayedAt": 1788250133927
492 }, 505 },
493 { 506 {
494 "id": "f84b8f044ec5", 507 "id": "f84b8f044ec5",
@@ -503,7 +516,7 @@ @@ -503,7 +516,7 @@
503 "likes": 0, 516 "likes": 0,
504 "createdAt": 1788120171725, 517 "createdAt": 1788120171725,
505 "promptEn": "constable bursts in and blocks the door, talks to a pale woman behind the screen", 518 "promptEn": "constable bursts in and blocks the door, talks to a pale woman behind the screen",
506 - "lastPlayedAt": 1788248607084 519 + "lastPlayedAt": 1788249899449
507 }, 520 },
508 { 521 {
509 "id": "5c364152e54c", 522 "id": "5c364152e54c",
@@ -563,7 +576,7 @@ @@ -563,7 +576,7 @@
563 "likes": 0, 576 "likes": 0,
564 "createdAt": 1788071067702, 577 "createdAt": 1788071067702,
565 "promptEn": "constable stands still, quietly says he won't make a sound, woman stays silent behind the screen", 578 "promptEn": "constable stands still, quietly says he won't make a sound, woman stays silent behind the screen",
566 - "lastPlayedAt": 1788247289944 579 + "lastPlayedAt": 1788249939841
567 }, 580 },
568 { 581 {
569 "id": "2e09fcd3d42c", 582 "id": "2e09fcd3d42c",
@@ -638,7 +651,7 @@ @@ -638,7 +651,7 @@
638 "likes": 0, 651 "likes": 0,
639 "createdAt": 1788026877547, 652 "createdAt": 1788026877547,
640 "promptEn": "a deity in gold crown and red veil, quietly judging you in a moonlit bridal chamber", 653 "promptEn": "a deity in gold crown and red veil, quietly judging you in a moonlit bridal chamber",
641 - "lastPlayedAt": 1788248094627 654 + "lastPlayedAt": 1788249765707
642 }, 655 },
643 { 656 {
644 "id": "d5f811737e95", 657 "id": "d5f811737e95",
@@ -683,7 +696,7 @@ @@ -683,7 +696,7 @@
683 "likes": 0, 696 "likes": 0,
684 "createdAt": 1788026569123, 697 "createdAt": 1788026569123,
685 "promptEn": "pale dream demon in a suit, reaching out a hand inside a dream train car", 698 "promptEn": "pale dream demon in a suit, reaching out a hand inside a dream train car",
686 - "lastPlayedAt": 1788248166697 699 + "lastPlayedAt": 1788250129929
687 }, 700 },
688 { 701 {
689 "id": "bd6e2b264243", 702 "id": "bd6e2b264243",
@@ -743,7 +756,7 @@ @@ -743,7 +756,7 @@
743 "likes": 0, 756 "likes": 0,
744 "createdAt": 1788026068497, 757 "createdAt": 1788026068497,
745 "promptEn": "black-haired prince in a red cloak, pressing down an execution order in the trial hall", 758 "promptEn": "black-haired prince in a red cloak, pressing down an execution order in the trial hall",
746 - "lastPlayedAt": 1788247147812 759 + "lastPlayedAt": 1788249833797
747 }, 760 },
748 { 761 {
749 "id": "0a5e37bb328c", 762 "id": "0a5e37bb328c",
@@ -758,7 +771,7 @@ @@ -758,7 +771,7 @@
758 "likes": 0, 771 "likes": 0,
759 "createdAt": 1788025642732, 772 "createdAt": 1788025642732,
760 "promptEn": "Vecna reaching out a claw in his lair in the Upside Down, red lightning", 773 "promptEn": "Vecna reaching out a claw in his lair in the Upside Down, red lightning",
761 - "lastPlayedAt": 1788246201053 774 + "lastPlayedAt": 1788249929837
762 }, 775 },
763 { 776 {
764 "id": "00862f966c3f", 777 "id": "00862f966c3f",
@@ -1133,7 +1146,7 @@ @@ -1133,7 +1146,7 @@
1133 "likes": 0, 1146 "likes": 0,
1134 "createdAt": 1788014099497, 1147 "createdAt": 1788014099497,
1135 "promptEn": "glass bridge game, exploiting a flaw to push back player 101", 1148 "promptEn": "glass bridge game, exploiting a flaw to push back player 101",
1136 - "lastPlayedAt": 1788248180707 1149 + "lastPlayedAt": 1788249885816
1137 }, 1150 },
1138 { 1151 {
1139 "id": "24576c264a25", 1152 "id": "24576c264a25",
@@ -1148,7 +1161,7 @@ @@ -1148,7 +1161,7 @@
1148 "likes": 0, 1161 "likes": 0,
1149 "createdAt": 1788013870849, 1162 "createdAt": 1788013870849,
1150 "promptEn": "glass bridge game, exploiting a flaw to push back player 101", 1163 "promptEn": "glass bridge game, exploiting a flaw to push back player 101",
1151 - "lastPlayedAt": 1788244557694 1164 + "lastPlayedAt": 1788249963847
1152 }, 1165 },
1153 { 1166 {
1154 "id": "dd12bbb55060", 1167 "id": "dd12bbb55060",
@@ -1178,7 +1191,7 @@ @@ -1178,7 +1191,7 @@
1178 "likes": 0, 1191 "likes": 0,
1179 "createdAt": 1788013632065, 1192 "createdAt": 1788013632065,
1180 "promptEn": "glass bridge game, held the goal but paid a price", 1193 "promptEn": "glass bridge game, held the goal but paid a price",
1181 - "lastPlayedAt": 1788247840412 1194 + "lastPlayedAt": 1788249933837
1182 }, 1195 },
1183 { 1196 {
1184 "id": "892b923eed29", 1197 "id": "892b923eed29",
@@ -1193,7 +1206,7 @@ @@ -1193,7 +1206,7 @@
1193 "likes": 0, 1206 "likes": 0,
1194 "createdAt": 1788013393463, 1207 "createdAt": 1788013393463,
1195 "promptEn": "guessed wrong in a survival game, got countered", 1208 "promptEn": "guessed wrong in a survival game, got countered",
1196 - "lastPlayedAt": 1788248362870 1209 + "lastPlayedAt": 1788250071902
1197 }, 1210 },
1198 { 1211 {
1199 "id": "7880a91928c6", 1212 "id": "7880a91928c6",
@@ -1253,7 +1266,7 @@ @@ -1253,7 +1266,7 @@
1253 "likes": 0, 1266 "likes": 0,
1254 "createdAt": 1788012679740, 1267 "createdAt": 1788012679740,
1255 "promptEn": "in the mental lair, exploiting a flaw to counter Vecna", 1268 "promptEn": "in the mental lair, exploiting a flaw to counter Vecna",
1256 - "lastPlayedAt": 1788245658603 1269 + "lastPlayedAt": 1788250124975
1257 }, 1270 },
1258 { 1271 {
1259 "id": "3913752bbe3a", 1272 "id": "3913752bbe3a",
@@ -1403,7 +1416,7 @@ @@ -1403,7 +1416,7 @@
1403 "likes": 0, 1416 "likes": 0,
1404 "createdAt": 1788010775613, 1417 "createdAt": 1788010775613,
1405 "promptEn": "facing Voldemort, stayed passive and got cornered", 1418 "promptEn": "facing Voldemort, stayed passive and got cornered",
1406 - "lastPlayedAt": 1788241054655 1419 + "lastPlayedAt": 1788249909833
1407 }, 1420 },
1408 { 1421 {
1409 "id": "795842efa4a1", 1422 "id": "795842efa4a1",
@@ -1583,7 +1596,7 @@ @@ -1583,7 +1596,7 @@
1583 "likes": 0, 1596 "likes": 0,
1584 "createdAt": 1788007915610, 1597 "createdAt": 1788007915610,
1585 "promptEn": "in the ruined city, exploiting a flaw to counter Tomura", 1598 "promptEn": "in the ruined city, exploiting a flaw to counter Tomura",
1586 - "lastPlayedAt": 1788244427575 1599 + "lastPlayedAt": 1788249919450
1587 }, 1600 },
1588 { 1601 {
1589 "id": "f67685cd6862", 1602 "id": "f67685cd6862",
@@ -1628,7 +1641,7 @@ @@ -1628,7 +1641,7 @@
1628 "likes": 0, 1641 "likes": 0,
1629 "createdAt": 1788007201908, 1642 "createdAt": 1788007201908,
1630 "promptEn": "breaking into the palace, Neferpitou stalling to protect the king", 1643 "promptEn": "breaking into the palace, Neferpitou stalling to protect the king",
1631 - "lastPlayedAt": 1788248014560 1644 + "lastPlayedAt": 1788249889814
1632 }, 1645 },
1633 { 1646 {
1634 "id": "628026375795", 1647 "id": "628026375795",
@@ -1718,7 +1731,7 @@ @@ -1718,7 +1731,7 @@
1718 "likes": 0, 1731 "likes": 0,
1719 "createdAt": 1788005778588, 1732 "createdAt": 1788005778588,
1720 "promptEn": "facing Frieza, held the goal but paid a price", 1733 "promptEn": "facing Frieza, held the goal but paid a price",
1721 - "lastPlayedAt": 1788247462098 1734 + "lastPlayedAt": 1788249925828
1722 }, 1735 },
1723 { 1736 {
1724 "id": "b96cc9762cf6", 1737 "id": "b96cc9762cf6",
@@ -1808,7 +1821,7 @@ @@ -1808,7 +1821,7 @@
1808 "likes": 0, 1821 "likes": 0,
1809 "createdAt": 1788004353928, 1822 "createdAt": 1788004353928,
1810 "promptEn": "facing Mahito, went in head-on and got seen through", 1823 "promptEn": "facing Mahito, went in head-on and got seen through",
1811 - "lastPlayedAt": 1788244924008 1824 + "lastPlayedAt": 1788250119920
1812 }, 1825 },
1813 { 1826 {
1814 "id": "971d80ec087c", 1827 "id": "971d80ec087c",
@@ -1928,7 +1941,7 @@ @@ -1928,7 +1941,7 @@
1928 "likes": 0, 1941 "likes": 0,
1929 "createdAt": 1788002691822, 1942 "createdAt": 1788002691822,
1930 "promptEn": "facing Reiner, held the goal but paid a price", 1943 "promptEn": "facing Reiner, held the goal but paid a price",
1931 - "lastPlayedAt": 1788244299472 1944 + "lastPlayedAt": 1788249915447
1932 }, 1945 },
1933 { 1946 {
1934 "id": "f65b15d67966", 1947 "id": "f65b15d67966",
@@ -2258,7 +2271,7 @@ @@ -2258,7 +2271,7 @@
2258 "likes": 0, 2271 "likes": 0,
2259 "createdAt": 1787762342686, 2272 "createdAt": 1787762342686,
2260 "promptEn": "woman tells him from behind the screen to go check outside, he steps out warily", 2273 "promptEn": "woman tells him from behind the screen to go check outside, he steps out warily",
2261 - "lastPlayedAt": 1788248000548 2274 + "lastPlayedAt": 1788250091902
2262 }, 2275 },
2263 { 2276 {
2264 "id": "47a6de809c61", 2277 "id": "47a6de809c61",
@@ -2288,7 +2301,7 @@ @@ -2288,7 +2301,7 @@
2288 "likes": 0, 2301 "likes": 0,
2289 "createdAt": 1787762311804, 2302 "createdAt": 1787762311804,
2290 "promptEn": "constable sits with a cup of water, slowly looking up at the woman behind the screen", 2303 "promptEn": "constable sits with a cup of water, slowly looking up at the woman behind the screen",
2291 - "lastPlayedAt": 1788246833570 2304 + "lastPlayedAt": 1788250038963
2292 }, 2305 },
2293 { 2306 {
2294 "id": "850f13881576", 2307 "id": "850f13881576",
@@ -2393,7 +2406,7 @@ @@ -2393,7 +2406,7 @@
2393 "likes": 0, 2406 "likes": 0,
2394 "createdAt": 1787724313620, 2407 "createdAt": 1787724313620,
2395 "promptEn": "first-person view bursting into the room, glancing back in fear, the woman startled", 2408 "promptEn": "first-person view bursting into the room, glancing back in fear, the woman startled",
2396 - "lastPlayedAt": 1788247658274 2409 + "lastPlayedAt": 1788249869811
2397 }, 2410 },
2398 { 2411 {
2399 "id": "81b6c3789111", 2412 "id": "81b6c3789111",
@@ -2498,7 +2511,7 @@ @@ -2498,7 +2511,7 @@
2498 "likes": 0, 2511 "likes": 0,
2499 "createdAt": 1787708653181, 2512 "createdAt": 1787708653181,
2500 "promptEn": "constable holds her gaze, quietly says \"go on\", then waits in silence", 2513 "promptEn": "constable holds her gaze, quietly says \"go on\", then waits in silence",
2501 - "lastPlayedAt": 1788244341508 2514 + "lastPlayedAt": 1788249737695
2502 }, 2515 },
2503 { 2516 {
2504 "id": "55f98ceec9e4", 2517 "id": "55f98ceec9e4",
@@ -2663,7 +2676,7 @@ @@ -2663,7 +2676,7 @@
2663 "likes": 0, 2676 "likes": 0,
2664 "createdAt": 1787674737743, 2677 "createdAt": 1787674737743,
2665 "promptEn": "constable slowly looks around the room, discovers her watching him motionlessly through the screen", 2678 "promptEn": "constable slowly looks around the room, discovers her watching him motionlessly through the screen",
2666 - "lastPlayedAt": 1788248444942 2679 + "lastPlayedAt": 1788249837798
2667 }, 2680 },
2668 { 2681 {
2669 "id": "c74118d0413f", 2682 "id": "c74118d0413f",
@@ -2708,7 +2721,7 @@ @@ -2708,7 +2721,7 @@
2708 "likes": 0, 2721 "likes": 0,
2709 "createdAt": 1787674695703, 2722 "createdAt": 1787674695703,
2710 "promptEn": "constable stops, faces the screen, quietly promises to keep his voice down", 2723 "promptEn": "constable stops, faces the screen, quietly promises to keep his voice down",
2711 - "lastPlayedAt": 1788247540173 2724 + "lastPlayedAt": 1788250023879
2712 }, 2725 },
2713 { 2726 {
2714 "id": "94dc455e26bf", 2727 "id": "94dc455e26bf",
@@ -2753,7 +2766,7 @@ @@ -2753,7 +2766,7 @@
2753 "likes": 0, 2766 "likes": 0,
2754 "createdAt": 1787674642139, 2767 "createdAt": 1787674642139,
2755 "promptEn": "constable forms hand seals and summons a giant toad out of smoke", 2768 "promptEn": "constable forms hand seals and summons a giant toad out of smoke",
2756 - "lastPlayedAt": 1788247129805 2769 + "lastPlayedAt": 1788250076972
2757 }, 2770 },
2758 { 2771 {
2759 "id": "e9a6320e18a9", 2772 "id": "e9a6320e18a9",
@@ -2783,7 +2796,7 @@ @@ -2783,7 +2796,7 @@
2783 "likes": 0, 2796 "likes": 0,
2784 "createdAt": 1787674639055, 2797 "createdAt": 1787674639055,
2785 "promptEn": "constable checks his reflection in the mirror, sees her behind his shoulder in it, turns around to find the screen empty", 2798 "promptEn": "constable checks his reflection in the mirror, sees her behind his shoulder in it, turns around to find the screen empty",
2786 - "lastPlayedAt": 1788246273115 2799 + "lastPlayedAt": 1788249777714
2787 }, 2800 },
2788 { 2801 {
2789 "id": "ebaf0dde3d9f", 2802 "id": "ebaf0dde3d9f",
@@ -3023,7 +3036,7 @@ @@ -3023,7 +3036,7 @@
3023 "likes": 0, 3036 "likes": 0,
3024 "createdAt": 1787615243753, 3037 "createdAt": 1787615243753,
3025 "promptEn": "robot arm picks up a red block and puts it down", 3038 "promptEn": "robot arm picks up a red block and puts it down",
3026 - "lastPlayedAt": 1788246909631 3039 + "lastPlayedAt": 1788249857808
3027 }, 3040 },
3028 { 3041 {
3029 "id": "d040eec16a88", 3042 "id": "d040eec16a88",
@@ -3038,7 +3051,7 @@ @@ -3038,7 +3051,7 @@
3038 "likes": 0, 3051 "likes": 0,
3039 "createdAt": 1787615242602, 3052 "createdAt": 1787615242602,
3040 "promptEn": "otome game male lead showcase PV", 3053 "promptEn": "otome game male lead showcase PV",
3041 - "lastPlayedAt": 1788247347993 3054 + "lastPlayedAt": 1788249753702
3042 }, 3055 },
3043 { 3056 {
3044 "id": "423a20afba5a", 3057 "id": "423a20afba5a",
@@ -3068,7 +3081,7 @@ @@ -3068,7 +3081,7 @@
3068 "likes": 0, 3081 "likes": 0,
3069 "createdAt": 1787615240988, 3082 "createdAt": 1787615240988,
3070 "promptEn": "clay fox sprints off a cliff, slow-mo leap over the canyon", 3083 "promptEn": "clay fox sprints off a cliff, slow-mo leap over the canyon",
3071 - "lastPlayedAt": 1788247880445 3084 + "lastPlayedAt": 1788249951846
3072 }, 3085 },
3073 { 3086 {
3074 "id": "db125dc6a831", 3087 "id": "db125dc6a831",
@@ -3128,7 +3141,7 @@ @@ -3128,7 +3141,7 @@
3128 "likes": 0, 3141 "likes": 0,
3129 "createdAt": 1787588545243, 3142 "createdAt": 1787588545243,
3130 "promptEn": "ergonomic office chair 360 showcase ad", 3143 "promptEn": "ergonomic office chair 360 showcase ad",
3131 - "lastPlayedAt": 1788248711178 3144 + "lastPlayedAt": 1788250058966
3132 }, 3145 },
3133 { 3146 {
3134 "id": "b0d258352c3c", 3147 "id": "b0d258352c3c",
@@ -3218,7 +3231,7 @@ @@ -3218,7 +3231,7 @@
3218 "likes": 0, 3231 "likes": 0,
3219 "createdAt": 1787588541726, 3232 "createdAt": 1787588541726,
3220 "promptEn": "woman opens the trunk on a desert road, takes out a bag", 3233 "promptEn": "woman opens the trunk on a desert road, takes out a bag",
3221 - "lastPlayedAt": 1788245330307 3234 + "lastPlayedAt": 1788250107920
3222 }, 3235 },
3223 { 3236 {
3224 "id": "97846542ab09", 3237 "id": "97846542ab09",
@@ -3397,7 +3410,7 @@ @@ -3397,7 +3410,7 @@
3397 "partition": "text", 3410 "partition": "text",
3398 "likes": 0, 3411 "likes": 0,
3399 "createdAt": 1787576506447, 3412 "createdAt": 1787576506447,
3400 - "lastPlayedAt": 1788247534166, 3413 + "lastPlayedAt": 1788250053889,
3401 "promptEn": "man does as she says but stays on guard" 3414 "promptEn": "man does as she says but stays on guard"
3402 }, 3415 },
3403 { 3416 {
@@ -3548,7 +3561,7 @@ @@ -3548,7 +3561,7 @@
3548 "likes": 0, 3561 "likes": 0,
3549 "createdAt": 1787542770522, 3562 "createdAt": 1787542770522,
3550 "promptEn": "clip cut to match a reference video's editing rhythm", 3563 "promptEn": "clip cut to match a reference video's editing rhythm",
3551 - "lastPlayedAt": 1788248438939 3564 + "lastPlayedAt": 1788249969849
3552 }, 3565 },
3553 { 3566 {
3554 "id": "f9286d694bad", 3567 "id": "f9286d694bad",
@@ -3608,7 +3621,7 @@ @@ -3608,7 +3621,7 @@
3608 "likes": 0, 3621 "likes": 0,
3609 "createdAt": 1787470101960, 3622 "createdAt": 1787470101960,
3610 "promptEn": "cute hand-drawn beagle dog making faces, game screen", 3623 "promptEn": "cute hand-drawn beagle dog making faces, game screen",
3611 - "lastPlayedAt": 1788248134665 3624 + "lastPlayedAt": 1788249793727
3612 }, 3625 },
3613 { 3626 {
3614 "id": "4067993ff824", 3627 "id": "4067993ff824",
@@ -3833,7 +3846,7 @@ @@ -3833,7 +3846,7 @@
3833 "likes": 0, 3846 "likes": 0,
3834 "createdAt": 1787450754171, 3847 "createdAt": 1787450754171,
3835 "promptEn": "protagonist leaps across rooftops fleeing pursuers", 3848 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
3836 - "lastPlayedAt": 1788246511317 3849 + "lastPlayedAt": 1788249973852
3837 }, 3850 },
3838 { 3851 {
3839 "id": "fd0183c54763", 3852 "id": "fd0183c54763",
@@ -3878,7 +3891,7 @@ @@ -3878,7 +3891,7 @@
3878 "likes": 0, 3891 "likes": 0,
3879 "createdAt": 1787442174982, 3892 "createdAt": 1787442174982,
3880 "promptEn": "protagonist leaps across rooftops fleeing pursuers", 3893 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
3881 - "lastPlayedAt": 1788248334845 3894 + "lastPlayedAt": 1788249819782
3882 }, 3895 },
3883 { 3896 {
3884 "id": "18105bc2900b", 3897 "id": "18105bc2900b",
@@ -4058,7 +4071,7 @@ @@ -4058,7 +4071,7 @@
4058 "likes": 0, 4071 "likes": 0,
4059 "createdAt": 1787412606465, 4072 "createdAt": 1787412606465,
4060 "promptEn": "protagonist leaps across rooftops fleeing pursuers", 4073 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
4061 - "lastPlayedAt": 1788246453270 4074 + "lastPlayedAt": 1788249769708
4062 }, 4075 },
4063 { 4076 {
4064 "id": "29a99dc412b2", 4077 "id": "29a99dc412b2",
@@ -4358,7 +4371,7 @@ @@ -4358,7 +4371,7 @@
4358 "likes": 0, 4371 "likes": 0,
4359 "createdAt": 1787326019290, 4372 "createdAt": 1787326019290,
4360 "promptEn": "misty Jiangnan old town at dawn, woman walking with an oil-paper umbrella", 4373 "promptEn": "misty Jiangnan old town at dawn, woman walking with an oil-paper umbrella",
4361 - "lastPlayedAt": 1788247508139 4374 + "lastPlayedAt": 1788249851805
4362 }, 4375 },
4363 { 4376 {
4364 "id": "fd8534ce588c", 4377 "id": "fd8534ce588c",
live.css
@@ -176,21 +176,26 @@ body { @@ -176,21 +176,26 @@ body {
176 color: var(--muted); 176 color: var(--muted);
177 padding: 12px 14px 6px; 177 padding: 12px 14px 6px;
178 } 178 }
179 -.chat-title-row { display: flex; align-items: center; justify-content: space-between; }  
180 -.nickname-edit-btn { 179 +.chat-identity-row {
  180 + display: flex;
  181 + align-items: center;
  182 + gap: 8px;
  183 + padding: 0 14px 6px;
  184 + font-size: 11.5px;
  185 + font-weight: 700;
  186 +}
  187 +.chat-identity-row #currentNickname { color: var(--accent); }
  188 +.chat-identity-row #changeNameBtn {
181 background: transparent; 189 background: transparent;
182 - border: 1px solid var(--border); 190 + border: none;
183 color: var(--muted); 191 color: var(--muted);
184 font-size: 11px; 192 font-size: 11px;
185 font-weight: 700; 193 font-weight: 700;
186 - text-transform: none;  
187 - letter-spacing: normal;  
188 - border-radius: 999px;  
189 - padding: 3px 10px; 194 + text-decoration: underline;
190 cursor: pointer; 195 cursor: pointer;
  196 + padding: 0;
191 } 197 }
192 -.nickname-edit-btn:hover { color: #fff; border-color: var(--muted); }  
193 -.nickname-edit-btn #currentNickname { color: var(--accent); } 198 +.chat-identity-row #changeNameBtn:hover { color: #fff; }
194 .chat-list { 199 .chat-list {
195 flex: 1; 200 flex: 1;
196 overflow-y: auto; 201 overflow-y: auto;
live.html
@@ -40,11 +40,12 @@ @@ -40,11 +40,12 @@
40 </div> 40 </div>
41 41
42 <aside class="right-col" id="rightCol" hidden> 42 <aside class="right-col" id="rightCol" hidden>
43 - <div class="section-title chat-title-row">  
44 - <span>聊天</span>  
45 - <button class="nickname-edit-btn" id="nicknameEditBtn">昵称 <span id="currentNickname">未设置</span> ✎</button>  
46 - </div> 43 + <div class="section-title">聊天</div>
47 <div class="chat-list" id="chatList"></div> 44 <div class="chat-list" id="chatList"></div>
  45 + <div class="chat-identity-row" id="chatIdentityRow" hidden>
  46 + <span id="currentNickname"></span>
  47 + <button id="changeNameBtn">change name</button>
  48 + </div>
48 <div class="chat-input-row"> 49 <div class="chat-input-row">
49 <input type="text" id="chatInput" placeholder="说点什么,或者想看什么…" maxlength="300" /> 50 <input type="text" id="chatInput" placeholder="说点什么,或者想看什么…" maxlength="300" />
50 <button id="chatSendBtn">发送</button> 51 <button id="chatSendBtn">发送</button>
@@ -97,7 +98,8 @@ const muteBtn = document.getElementById(&quot;muteBtn&quot;); @@ -97,7 +98,8 @@ const muteBtn = document.getElementById(&quot;muteBtn&quot;);
97 const nicknameModal = document.getElementById("nicknameModal"); 98 const nicknameModal = document.getElementById("nicknameModal");
98 const nicknameInput = document.getElementById("nicknameInput"); 99 const nicknameInput = document.getElementById("nicknameInput");
99 const nicknameConfirmBtn = document.getElementById("nicknameConfirmBtn"); 100 const nicknameConfirmBtn = document.getElementById("nicknameConfirmBtn");
100 -const nicknameEditBtn = document.getElementById("nicknameEditBtn"); 101 +const chatIdentityRow = document.getElementById("chatIdentityRow");
  102 +const changeNameBtn = document.getElementById("changeNameBtn");
101 const currentNickname = document.getElementById("currentNickname"); 103 const currentNickname = document.getElementById("currentNickname");
102 const clientId = Math.random().toString(36).slice(2); 104 const clientId = Math.random().toString(36).slice(2);
103 105
@@ -130,7 +132,8 @@ function getIdentity() { @@ -130,7 +132,8 @@ function getIdentity() {
130 } 132 }
131 function updateNicknameLabel() { 133 function updateNicknameLabel() {
132 const existing = getIdentity(); 134 const existing = getIdentity();
133 - currentNickname.textContent = existing ? existing.nickname : "未设置"; 135 + chatIdentityRow.hidden = !existing;
  136 + if (existing) currentNickname.textContent = existing.nickname;
134 } 137 }
135 138
136 // Shared by first-time setup and the always-visible "昵称 ✎" edit button. 139 // Shared by first-time setup and the always-visible "昵称 ✎" edit button.
@@ -167,7 +170,7 @@ function ensureIdentity() { @@ -167,7 +170,7 @@ function ensureIdentity() {
167 }); 170 });
168 } 171 }
169 172
170 -nicknameEditBtn.addEventListener("click", async () => { 173 +changeNameBtn.addEventListener("click", async () => {
171 const existing = getIdentity(); 174 const existing = getIdentity();
172 const nickname = await openNicknameModal(existing ? existing.nickname : ""); 175 const nickname = await openNicknameModal(existing ? existing.nickname : "");
173 const uid = existing ? existing.uid : crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`; 176 const uid = existing ? existing.uid : crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
@@ -176,6 +179,10 @@ nicknameEditBtn.addEventListener(&quot;click&quot;, async () =&gt; { @@ -176,6 +179,10 @@ nicknameEditBtn.addEventListener(&quot;click&quot;, async () =&gt; {
176 updateNicknameLabel(); 179 updateNicknameLabel();
177 }); 180 });
178 181
  182 +// First click into the chat box is what prompts for a nickname — not just
  183 +// hitting send — so the identity row above the input appears right away.
  184 +chatInput.addEventListener("focus", () => ensureIdentity());
  185 +
179 updateNicknameLabel(); 186 updateNicknameLabel();
180 187
181 function renderBrowseList() { 188 function renderBrowseList() {