Spaces:
Running
Running
File size: 5,936 Bytes
06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 ef7d187 06f5c28 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
from fasthtml.common import *
from fasthtml.svg import *
from svgs import fasthtml_logo
from fasthtml_hf import setup_hf_backup
app,rt = fast_app(
live=True,
id=int,
title=str,
done=bool,
pk='id',
hdrs=(Script(src="https://unpkg.com/alpinejs", defer=True), Link(rel="stylesheet", href="/public/app.css", type="text/css"),),
pico=False,
debug=True,
)
js = """
function game() {
const cds = [];
let id = 1;
for (let i = 1; i <= 12; i++) {
cds.push({ id: id++, flipped: false, cleared: false, card: i });
cds.push({ id: id++, flipped: false, cleared: false, card: i });
}
cds.sort((a, b) => 0.5 - Math.random());
return {
card_clicks: 0,
cheats: 3,
cards: cds,
get flippedCards() {
return this.cards.filter(card => card.flipped);
},
flipCard(card) {
this.card_clicks += 1;
if( card.cleared ) { return; }
if( this.flippedCards.length <= 1 ) { card.flipped = ! card.flipped; }
if( this.flippedCards.length === 2 ) {
if( this.flippedCards[0].card === this.flippedCards[1].card ) {
this.flippedCards.forEach(card => {
card.cleared = true;
card.flipped = false;
});
} else {
if( card.id !== this.flippedCards[0].id && card.id !== this.flippedCards[1].id ) {
this.flippedCards.forEach(card => {
card.flipped = false;
});
card.flipped = ! card.flipped;
} else {
setTimeout((cd, fl) => {
fl.forEach(card => {
card.flipped = false;
});
}, 1000, card, this.flippedCards);
}
}
}
},
restart() {
this.cards.forEach(c => {
c.flipped = false;
c.cleared = false;
});
this.cheats = 3;
this.card_clicks = 0;
setTimeout(() => {
this.cards.sort((a, b) => 0.5 - Math.random());
}, 500);
},
cheat() {
if( this.cheats >= 1 ) {
this.cheats -= 1;
this.cards.forEach(c => {
c.flipped = true;
});
setTimeout(() => {
this.cards.forEach(c => {
c.flipped = false;
});
}, 750);
}
},
};
}
"""
def cards():
return Template(
Div(
Div(
Div(
NotStr(fasthtml_logo),
cls='flip-card-front'
),
Div(
Img(
#src='/assets/card_imgs/' + card_num + '.png',
**{":src": "'/assets/card_imgs/' + card.card + '.png'"},
),
cls='flip-card-back'
),
cls='flip-card-inner',
**{":class": "{'flip-rotate-y-180': card.flipped || card.cleared}"},
),
tabindex='0',
cls='flip-card',
**{"@click": "flipCard(card)"},
**{":class": "{'flip-cleared': card.cleared}"},
),
x_for='card in cards',
id="fr",
data_something="123"
)
@rt('/')
def get(): return Title('Card Memory Game in FastHTML'), Div(
Section(
Div(
H1('Card Memory Game', cls='text-4xl md:text-6xl font-bold mb-4'),
P('Built with FastHTML, HTMX, TailwindCSS, and AlpineJS.', cls='text-lg md:text-2xl'),
cls='text-center text-white px-6 md:px-12 drop-shadow-lg'
),
cls='min-h-[300px] flex items-center justify-center bg-gradient-to-r from-[#3cdd8c] to-[#ffdb6d]'
),
Section(
Div(
Div(
Div(
cards(),
cls='grid grid-cols-6 gap-4 w-[944px]'
),
),
cls='flex items-center justify-center mt-10'
),
Div(
Div(
Div(),
cls='flex items-center justify-center my-5 font-bold',
**{"x-text": "'Card clicks: ' + card_clicks"},
),
Div(
A(
'Restart Game',
cls='bg-white text-[#3cdd8c] font-semibold px-6 py-3 rounded-lg shadow-lg hover:bg-gray-100 transition',
**{"x-on:click.prevent": "restart()"},
),
A(
cls='bg-white text-[#3cdd8c] font-semibold px-6 py-3 rounded-lg shadow-lg hover:bg-gray-100 transition',
**{"x-on:click.prevent": "cheat()"},
**{"x-text": "'Cheat Mode! (' + cheats + ')'"},
),
cls='flex items-center justify-center gap-4'
),
Div(
'Reveal all the matching pairs of cards in the fewest clicks possible.',
cls='mt-6 flex items-center justify-center gap-4'
),
Div(
'Click the \'Cheat Mode\' button to reveal all tiles, but you only have three per game so use wisely!',
cls='flex items-center justify-center gap-4'
),
),
cls='mb-20',
x_data='game()',
),
Footer(
A('Created by David Gwyer - Follow me on X', href="https://x.com/dgwyer", _target="_blank", cls="drop-shadow-lg text-lg"),
cls='bg-gray-800 text-white text-center py-8'
),
cls='bg-gray-100 text-gray-800'
), Script(js)
setup_hf_backup(app)
serve(reload_includes=["*.css"])
|