diff --git a/apps/audio-bro.coffee b/apps/audio-bro.coffee index ae3e9f8..0e659a7 100644 --- a/apps/audio-bro.coffee +++ b/apps/audio-bro.coffee @@ -5,7 +5,7 @@ Model = require "model" module.exports = -> # Global system - {ContextMenu, MenuBar, Modal, Progress, Util:{parseMenu}, Window} = system.UI + {ContextMenu, MenuBar, Modal, Observable, Progress, Util:{parseMenu}, Window} = system.UI {Achievement} = system Achievement.unlock "Pump up the jam" @@ -14,8 +14,11 @@ module.exports = -> audio.controls = true audio.autoplay = true + filePath = Observable() + handlers = Model().include(FileIO).extend loadFile: (blob) -> + filePath blob.path audio.src = URL.createObjectURL blob exit: -> @@ -31,7 +34,11 @@ module.exports = -> handlers: handlers windowView = Window - title: "Audio Bro" + title: -> + if path = filePath() + "Audio Bro - #{path}" + else + "Audio Bro" content: audio menuBar: menuBar.element width: 308 diff --git a/issues/2016-12.coffee b/issues/2016-12.coffee index a9497b9..a2abea0 100644 --- a/issues/2016-12.coffee +++ b/issues/2016-12.coffee @@ -44,7 +44,7 @@ module.exports = -> area: issueTag .then (data) -> ajax - url: "https://whimsy-space.gomix.me/comments" + url: "https://whimsy-space.glitch.me/comments" data: JSON.stringify(data) headers: "Content-Type": "application/json" @@ -53,7 +53,7 @@ module.exports = -> handlers.viewComments() viewComments: -> - ajax.getJSON "https://whimsy-space.gomix.me/comments/#{issueTag}" + ajax.getJSON "https://whimsy-space.glitch.me/comments/#{issueTag}" .then (data) -> data = data.reverse() diff --git a/issues/2017-04.coffee b/issues/2017-04.coffee new file mode 100644 index 0000000..1ea55e0 --- /dev/null +++ b/issues/2017-04.coffee @@ -0,0 +1,177 @@ +Model = require "model" +Chateau = require "../apps/chateau" +Contrasaurus = require "../apps/contrasaurus" +PixiePaint = require "../apps/pixel" +Spreadsheet = require "../apps/spreadsheet" +TextEditor = require "../apps/text-editor" +MyBriefcase = require "../apps/my-briefcase" + +Social = require "../social/social" + +{parentElementOfType, emptyElement} = require "../util" + +module.exports = -> + {ContextMenu, MenuBar, Modal, Progress, Util:{parseMenu}, Window} = system.UI + {Achievement, ajax} = system + + visitedAreas = + bikes: false + izzy: false + residue: false + chateau: false + cheevo: false + briefcase: false + podcast: false + + visit = (area) -> + visitedAreas[area] = true + + visitedAll = Object.keys(visitedAreas).every (key) -> + visitedAreas[key] + + if visitedAll + Achievement.unlock "Cover-2-cover 4: Fast & Furious" + + system.writeFile "issue-4/izzy.txt", new Blob [require "../stories/izzy"], type: "text/plain" + system.writeFile "issue-4/residue.txt", new Blob [require "../stories/residue"], type: "text/plain" + + downloadBikes = -> + ["and-yet-they-rode-bikes.md", "infog.png", "lanes.png", "totally-a.html"].forEach (path) -> + ajax + url: "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/bikes/#{path}" + responseType: "blob" + .then (blob) -> + system.writeFile "issue-4/bikes/#{path}", blob + + downloadBikes() + + ajax + url: "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/public/music/Funkytown.mp3" + responseType: "blob" + .then (blob) -> + system.writeFile "issue-4/Funkytown.mp3", blob + blob.path = "/issue-4/Funkytown.mp3" + system.open blob + + system.readFile "issue-4/zinecast1.mp3" + .then -> + ; # Zinecast exists, don't redownload + .catch -> + ajax + url: "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/public/podcasts/zinecast1.mp3" + responseType: "blob" + .then (blob) -> + system.writeFile "issue-4/zinecast1.mp3", blob + blob.path = "/issue-4/zinecast1.mp3" + + system.Achievement.unlock "Issue 4" + + handlers = Model().include(Social).extend + area: -> + "2017-04" + + zinecast1: -> + visit "podcast" + system.readFile "issue-4/zinecast1.mp3" + .then system.open + + bikes: -> + visit "bikes" + system.readFile "issue-4/bikes/and-yet-they-rode-bikes.md" + .then system.open + + chateau: -> + visit "chateau" + app = Chateau(system) + document.body.appendChild app.element + + achievementStatus: -> + visit "cheevo" + cheevoElement = system.Achievement.progressView() + cheevoElement.style.width = "100%" + cheevoElement.style.padding = "1em" + + system.Achievement.unlock "Check yo' self" + + windowView = Window + title: "Cheevos" + content: cheevoElement + width: 640 + height: 480 + + document.body.appendChild windowView.element + + myBriefcase: -> + visit "briefcase" + app = MyBriefcase() + document.body.appendChild app.element + + izzy: -> + Achievement.unlock "Izzy" + visit "izzy" + storyWindow = StoryWindow("Izzy", require("../stories/izzy")) + + document.body.appendChild storyWindow.element + + residue: -> + Achievement.unlock "Residue" + visit "residue" + + storyWindow = StoryWindow("Residue", require("../stories/residue")) + + document.body.appendChild storyWindow.element + + funkytown8bitRemix: -> + system.readFile "issue-4/Funkytown.mp3" + .then system.open + + menuBar = MenuBar + items: parseMenu """ + [A]pps + [C]hateau + My [B]riefcase + [M]usic + [F]unkytown (8-bit Remix) + [Z]inecast 1 + [S]tories + [B]ikes + [I]zzy + [R]esidue + #{Social.menuText} + [H]elp + [A]chievement Status + """ + handlers: handlers + + content = document.createElement "content" + content.style = "width: 100%; height: 100%" + + img = document.createElement "img" + img.src = "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/public/images/708e9398a4b4bea08d7c61ff7a0f863f.gif" + img.style = "width: 100%; height: 100%" + + windowView = Window + title: "ZineOS Volume 1 | Issue 4 | DISCO TECH | March 2017" + content: img + menuBar: menuBar.element + width: 480 + height: 600 + x: 64 + y: 64 + + windowView.element.querySelector('viewport').style.overflow = "initial" + + document.body.appendChild windowView.element + +StoryWindow = (title, text) -> + div = document.createElement "div" + div.textContent = text + div.style.padding = "1em" + div.style.whiteSpace = "pre-wrap" + div.style.textAlign = "justify" + + system.UI.Window + title: title + content: div + width: 380 + height: 480 diff --git a/main.coffee b/main.coffee index 2d59197..d1c740a 100644 --- a/main.coffee +++ b/main.coffee @@ -15,6 +15,10 @@ style = document.createElement "style" style.innerHTML = Style.all + "\n" + require("./style") document.head.appendChild style +VersionTemplate = require "./templates/version" +document.body.appendChild VersionTemplate + version: "v0.4.00.950a" + # Desktop Explorer = require "./apps/explorer" document.body.appendChild Explorer() @@ -23,9 +27,10 @@ system.writeFile "feedback.exe", new Blob [""], type: "application/exe" system.writeFile "issue-1/zine1.exe", new Blob [""], type: "application/exe" system.writeFile "issue-2/zine2.exe", new Blob [""], type: "application/exe" system.writeFile "issue-3/zine3.exe", new Blob [""], type: "application/exe" +system.writeFile "issue-4/zine4.exe", new Blob [""], type: "application/exe" system.writeFile "My Briefcase", new Blob [""], type: "application/briefcase" -require("./issues/2017-03")() +require("./issues/2017-04")() system.autoboot() # system.dumpModules() diff --git a/social/social.coffee b/social/social.coffee index 1fa8ae8..fb1d267 100644 --- a/social/social.coffee +++ b/social/social.coffee @@ -14,7 +14,7 @@ module.exports = (I, self) -> area: self.area() .then (data) -> ajax - url: "https://whimsy-space.gomix.me/comments" + url: "https://whimsy-space.glitch.me/comments" data: JSON.stringify(data) headers: "Content-Type": "application/json" @@ -23,7 +23,7 @@ module.exports = (I, self) -> self.viewComments() viewComments: -> - ajax.getJSON "https://whimsy-space.gomix.me/comments/#{self.area()}" + ajax.getJSON "https://whimsy-space.glitch.me/comments/#{self.area()}" .then (data) -> data = data.reverse() diff --git a/stories/izzy.coffee b/stories/izzy.coffee new file mode 100644 index 0000000..83265f1 --- /dev/null +++ b/stories/izzy.coffee @@ -0,0 +1,61 @@ +module.exports = """ +“Izzy, your grandma is here!” Izzy jumped up from where she was seated on the classroom floor chatting with her friends during after-school care, and she ran to her grandmother to give her a huge hug. + +“Have a good weekend,” her teacher said as Izzy grabbed her backpack. +“You too!” Izzy called, as she ran for the parking lot with Grandma close behind. She nearly flew through the school gate. + +“Wait for me before you cross the street!” Grandma shouted to Izzy. +“Sorry,” Izzy replied as Grandma caught up to her. + +They crossed over to where Grandpa was leaning against their 1973 El Camino. He swung Izzy up and spun her around. + +“Did you have a good day, kiddo?” +“Yeah! I finished The BFG and I got to draw my favorite part as a poster and share it with the class,” Izzy said proudly. +“Sounds great. Did you try to draw in the style of Quentin Blake, or did you use your own style?” Grandpa asked. +“Well, I tried pretty hard to draw like Quentin Blake, but it’s hard to draw like other artists. I didn’t like how it looked so I started over by just reading the description again and imagining it in my head. I’ll show you next week when I bring it home.” + +Izzy lowered her backpack into a wooden orange crate in the truck bed of the El Camino. Her navy-blue violin case, a small amplifier, and a black bag already sat in the crate. The crate nestled in between a variety of potted plants which took up the remaining space in the bed. Izzy plucked a few ripe cherry tomatoes and some snow peas from their respective vines, which twined around cages in a large planter close to the cab’s rear window. She ran her fingers through the thyme and mint spilling out of smaller planters closer to the tailgate and breathed in, relishing the pungent and spicy smells. She loved her grandparents’ mobile garden. + +She munched her snack as she climbed into the front seat of the El Camino and slid in next to Grandma, who sat in the driver’s seat. Grandpa placed three garment bags on Izzy’s lap, and then slid in beside her, sandwiching Izzy in between her grandparents. + +“Be careful not to get any tomato juice on the garment bags,” Grandpa cautioned. +“I know. I’ll be careful.” Izzy replied. +“All right. Sorry it’s such a tight fit today!” Grandpa smiled at Izzy. “Are you excited?” +“Yeah! I can’t wait until we get to the boardwalk! Everyone is going to love our show!” +“Well, then!” Grandma exclaimed. “Let’s go!” + +The El Camino’s engine roared to life and Grandma maneuvered the car onto the road. With both windows down, the breeze ruffled everyone’s hair, and as they neared their destination, the fresh scent of the ocean wafted in, filling Izzy’s nostrils with the salty, damp aroma. The plants in the back swayed gently back and forth in time with the rhythm of the car’s motion, and their planters were so tightly arranged that nothing slid around. + +Grandma pulled into a perfect parking space close to the boardwalk at the beachfront parking lot. Grandpa carried the garment bags; Izzy carried her backpack and violin, and Grandma carried the black bag and the amplifier. + +“Nice car!” a voice called to them. They turned to see a young man and woman wearing wetsuits and loading surfboards into the back of their SUV. +“Thanks!” Grandpa called back. The two surfers smiled at them. Izzy glowed. She loved the way her grandparents brought joy everywhere they went. + +The sun was beginning to set over the ocean, creating an air of magic. Izzy and her grandparents walked the short distance to their pre-chosen destination: a bench that overlooked the water, adjoining a large, wide sidewalk upon which Friday night foot traffic was beginning to accumulate. + +A nearby planter contained palm trees and succulents, as well as a small electrical outlet on one side. Grandma pulled an orange extension cord from her black bag, and plugged it in. She carefully duct-taped the cord to the ground for safety as she ran the cord up to the bench. Izzy plugged her amplifier in the extension cord and began setting up her equipment. + +“I’m going to go get changed,” said Grandpa to Grandma, taking his garment bag and walking in the direction of the restrooms. As Izzy began tuning her violin a few minutes later, Grandpa appeared wearing a leisure suit that had a complicated design made of conductive fabric circles and lines stitched together in that turned his costume into a drum pad, which connected wirelessly with the amplifier. + +The equipment setup complete, Grandpa began do a final check of his suit while Izzy and Grandma took their turn to change as well. A short time later, they emerged, resplendent in their own costumes. + +Grandma wore a long-sleeved, tight-fitting silver dress that had fiber optic filaments running vertically along her body and dangling beyond the bottom of the dress. She had not yet switched on the battery pack, and the dress appeared at first to be rather unassuming. However, the headdress she was wearing was quite the opposite. Nestled in Grandma’s big hairdo was a variety of feathers, delicately coiled wire shapes, and more fiber optics that skimmed the top of her head before shooting up like the crest of a rainforest bird. Dramatic, dark eyeliner, silver eye shadow, and silver platform shoes completed the look. + +The simple cut of Izzy’s dress accentuated the beautiful movement of the fabric. A fitted bodice gave way to a flared skirt. She twirled, and the purple and blue dip-dyed fabric swirled in response around her knees. Opting to keep her costume simple for ease of playing her violin, it had no electronics. The bodice was adorned with sequins she had painstakingly glued in an intricate pattern, which, like a disco ball, would reflect the lights from the small footlight set up next to her. In Izzy’s hair was a small feather and fiber optic fascinator, like Grandma’s but on a smaller scale. + +Izzy did a quick, final sound check. “Ready?” she asked. +“Let’s do it!” grinned Grandma and Grandpa. + +Months of effort coalesced into one moment as the sun finally dipped below the horizon, sending the boardwalk into twilight. Grandma and Grandpa switched on their battery packs, and Grandma’s dress lit up. Izzy switched on her footlight, nodded to Grandma and Grandpa, and began to play. + +Inspired by her hero Zoë Keating, Izzy began to loop snippets of her violin with her loop pedal. She built sound after sound up to a fast-paced, catchy, danceable beat, while Grandpa and Grandma began to dance. Grandma’s fiber optics began to pulse with the rhythm of Izzy’s music and Grandpa’s drum pad leisure suit. They whirled and spun, and even Izzy swayed and swirled with the music as she played. + +A crowd began to form, cheering on the pop-up discotheque. They clapped in time to the music, delighted every time Grandma’s skirt sent pinpricks of light racing around her knees, and murmured in excitement at the intricate movements Grandpa made to keep the drums thumping. As the song ended, the crowd exploded with whoops and shouts, and several people made donations into Izzy’s violin case. The family took a bow, and launched into another song, causing the crowd to cheer yet again. + +Like any moment that has been anticipated for so long, it seemed to last but the blink of an eye. When the last song ended, the crowd drifted away on the final, lingering notes from Izzy’s violin. As Grandma and Grandpa started to pack up, Izzy took a dime out of the violin case, her favorite coin because it was the smallest, and darted to the fountain down the boardwalk. She pitched the coin into the dark water that reflected the stars. + +“What did you wish for?” Grandpa asked as Izzy returned. +“Not telling,” Izzy replied. + +She slipped her small hand into Grandpa’s, and the other into Grandma’s, and they walked back to the El Camino. +""" \ No newline at end of file diff --git a/stories/residue.coffee b/stories/residue.coffee new file mode 100644 index 0000000..02a47c6 --- /dev/null +++ b/stories/residue.coffee @@ -0,0 +1,79 @@ +module.exports = """ +\u200b RESIDUE + ======= + +Jules, my friend, used to take her new +car to Viretta Park. After a workday +filled with tickets and meetings, she +sometimes drove the five miles to this +one-block wide, one-block tall park at +the northeast coast of the city where +people prospered. There, tourists via +Ubers and Lyfts came to see the Kurt +Cobain bench. But Jules would arrive at +the park and drive past. She would not +stop. She would not get out. You cannot +see the bench from the road. It was +usually dark after work. She told no one +about these trips until years later. + +Jules, our protagonist, (as far as she +could figure) had no conscious logic for +her actions. Without it the story +refused to hang together. It was a +sequence of events united by space and +time but lacking guts hearts or brains. +It was a propulsion without a +propellant. It defied narrative +structure and, without it, lacked +rhythm. Jules, being a capable +self-aware adult, knew she was acting +out of an impulse but it seemed to her +that the situation warranted impulse. +And, at that time and at the time this +was written, gas was cheap. I can safely +say also that she was not sad; she was +not one of those people who indulged in +the habit of moping about events beyond +their control. Some people are just +strong this way. + +In my presence Jules narrated the story +with the blank point of view of an +omniscient witness. There was a lull in +the conversation, this story was told, +and then we moved on. She wore a thin +jacket and a wry frown and we were high, +more high than usual. I, after giving it +some consideration, had a grocery list +of questions. Why Kurt Cobain; why +didn't you tell me earlier; and did you +do it to feel an impossible, cosmic +connection to something bigger than +yourself, a feeling for which I cannot +do justice but can tell you that, for +me, is close to the sensation of an +egg's cracking against the chest +cavity's outer wall. But from looking at +her I knew then, just as she had always +known, it was not as if there were +answers and she were ignorant of them. +There just were no answers. At the time +these events I am writing about took +place, she was stuck in a temporary city +at a temporary time of her life. In my +country, where you work for years and +years in search of permanent residence +status and where adults values +friendship but few pursue them, it seems +harder than other places to let out +these prickly stories. I imagine people +all around me have them, though – yarn +wound and knotted by fingers +absentmindedly rubbing the threads +together. + +After eighteen months, Jules packed up +all her furniture and moved away. She +drove all the way through America. +""" diff --git a/style.styl b/style.styl index aed454e..e4d1b82 100644 --- a/style.styl +++ b/style.styl @@ -1,4 +1,5 @@ body + color: rgba(0, 0, 0, 0.87) overflow: hidden h1 @@ -40,6 +41,7 @@ explorer padding: 0.5em user-select: none width: 100% + z-index: 1 > file, > folder display: inline-block @@ -208,3 +210,11 @@ achievement-badge &.achieved border: 1px solid blue color: blue + +version + bottom: 1em + display: block + font-weight: bold + pointer-events: none + position: absolute + right: 1em diff --git a/system.coffee b/system.coffee index ce707f0..a022464 100644 --- a/system.coffee +++ b/system.coffee @@ -15,6 +15,7 @@ MountFS = require "./lib/mount-fs" uniq = (array) -> Array.from new Set array +Ajax = require "ajax" Model = require "model" Achievement = require "./system/achievement" Associations = require "./system/associations" @@ -31,6 +32,7 @@ module.exports = (dbName='zine-os') -> self.include(Achievement, Associations, SystemModule, Template) self.extend + ajax: Ajax() fs: fs require: require @@ -82,8 +84,7 @@ module.exports = (dbName='zine-os') -> urlForPath: (path) -> fs.read(path) - .then ({blob}) -> - URL.createObjectURL(blob) + .then URL.createObjectURL # NOTE: These are experimental commands to run code execJS: (path) -> diff --git a/system/achievement.coffee b/system/achievement.coffee index ed23557..b3ae6bd 100644 --- a/system/achievement.coffee +++ b/system/achievement.coffee @@ -63,6 +63,26 @@ achievementData = [{ icon: "🈹" group: "Issue 3" description: "Read 'Blue Light Special'" +}, { + text: "Issue 4" + icon: "📰" + group: "Issue 4" + description: "View Issue 4" +}, { + text: "Cover-2-cover 4: Fast & Furious" + icon: "📗" + group: "Issue 4" + description: "Read the entire issue" +}, { + text: "Izzy" + icon: "🈹" + group: "Issue 4" + description: "Read 'Izzy'" +}, { + text: "Residue" + icon: "🈹" + group: "Issue 4" + description: "Read 'Residue'" }, { # Apps text: "Notepad.exe" icon: "📝" diff --git a/system/associations.coffee b/system/associations.coffee index caaf91d..e5cf81e 100644 --- a/system/associations.coffee +++ b/system/associations.coffee @@ -14,7 +14,7 @@ openWith = (App) -> {path} = file app = App() - system.readFile file.path + system.readFile path .then (blob) -> app.loadFile(blob, path) @@ -25,6 +25,12 @@ module.exports = (I, self) -> # The first handler that matches is the default handler, the rest are available # from context menu handlers = [{ + name: "Markdown" # TODO: This renders html now too, so may need a broader name + filter: (file) -> + file.path.match(/\.md$/) or + file.path.match(/\.html$/) + fn: openWith(Markdown) + }, { name: "Ace Editor" filter: (file) -> file.path.match(/\.coffee$/) or @@ -56,12 +62,6 @@ module.exports = (I, self) -> sourceProgram = CoffeeScript.compile coffeeSource, bare: true system.spawn sourceProgram, file.path - }, { - name: "Markdown" # TODO: This renders html now too, so may need a broader name - filter: (file) -> - file.path.match(/\.md$/) or - file.path.match(/\.html$/) - fn: openWith(Markdown) }, { name: "Notepad" filter: (file) -> @@ -114,6 +114,12 @@ module.exports = (I, self) -> file.path.match /zine3\.exe$/ fn: -> require("../issues/2017-03")() + }, { + name: "zine4.exe" + filter: (file) -> + file.path.match /zine4\.exe$/ + fn: -> + require("../issues/2017-04")() }, { name: "feedback.exe" filter: (file) -> diff --git a/templates/version.jadelet b/templates/version.jadelet new file mode 100644 index 0000000..56a406e --- /dev/null +++ b/templates/version.jadelet @@ -0,0 +1,2 @@ +version + span= "ZineOS #{@version} ⌊ALPHA⌉"