/* index! Here's so much code that we keep it in a separate file. */ var layout = new AggressiveLayout({ textConversion : marked, API_URL: "feeds_api_client.php" }); AggressiveLayout.prototype.setupFunction = function() { this.setupFeeds(); this.setupLogin(); //from feedsDefaults this.loginAPI.setupFunction() this.setCSSFromSelector(".iconImage", { width : "256px", margin: "auto", display: "block" }) //this.setCSSFromSelector("h1", { textAlign : "center" }) this.setCSSFromSelector(".welcomeDiv", { padding: "10px" }) this.setCSSFromSelector(".separator", { position: "relative", width: "100%", margin: "20px 0px 20px 0px", borderBottomWidth: "1px", borderBottomStyle: "solid", borderBottomColor: "rgb(0, 0, 0), left: 0%" }) this.setCSSFromSelector(".icon_container", { cssFloat: "right", }) this.setCSSFromSelector(".floatingLogo", { display: "inline-block", width: "50vw", paddingLeft: "10px", maxWidth : "400px", verticalAlign: "bottom" }) //I don't want padding on the center div since the image //is this used? this.setCSSFromSelector(".centerDiv", { padding: "10px 10px 0px 10px", }) //NOTE: You should use flexBox for this! this.setCSSFromSelector(".iconText", { fontWeight: 400, padding: "5px 0px" }) this.applyCSS({ "video": { display: "block", margin: "auto", maxWidth: "100%" }, ".videoChild": { maxWidth: "30%", display: "inline-block", margin: "4%" }, ".videoHolder": { textAlign: "center" }, //here we have the cards ".centered": { textAlign: "center" }, ".cardContainer": { display: "flex", flexWrap: "wrap", justifyContent: "space-evenly", }, ".cardChild": { maxWidth: "300px", margin: "0 5px 2em 5px", padding: "1.5em", border: "0px solid black", borderRadius: "10px", boxShadow: "0px 0px 10px 2px rgba(0,0,0,0.2)", }, //".cardChildImage": { display: "block", margin: "auto", maxWidth: "50px", maxHeight: "50px" }, ".cardChildImage": { display: "block", margin: "auto", fontSize: "50px", textAlign: "center" }, ".cardChild > h2": { textAlign: "center", marginTop: "0px" }, ".cardChild p": { marginBottom: "5px" } }) var phoneSheet = this.createStyleSheet({mediaType: AUTO_CONST.phone}) this.applyCSS({ ".videoChild": { maxWidth: "50%" }, ".cardChild": { maxWidth: "42%", margin: "2.5%" }, }, phoneSheet) var smallerPhoneSheet = this.createStyleSheet({mediaType: AUTO_CONST.smallerPhone}) this.applyCSS({ ".videoChild": { maxWidth: "100%" }, ".cardChild": { maxWidth: "90%", margin: "0px 0px 2em 0px" }, }, smallerPhoneSheet) //we can turn svg to json like this, then build svg elements, but just for colors? Wouldn't it be easier to just generate two versions? //https://github.com/elrumordelaluz/svgson //we can have one simple template and reuse it! var header = new StaticTemplate({ children: [ this.mainTitleSmall, { type: "h1", html: this.nameWithTagLine, style : { textAlign : "center", color: this.feedsBlueColor, fontWeight: "bold", fontSize : "1.5em" } }, ]}) var templateOptions = { layout : this, header: header, noBackground : 1, imageColor : "white", lessSpaciousLayout: 1, firstStyle: { }, secondStyle: { backgroundColor: layout.feedsBlueColor, color: "white" }, opaqueFooter: 1, classPrefix: "main", imageColor: this.feedsBlueColor } this.template = new FixedBackgroundTemplate(templateOptions); this.noPaddingClassName = "centerDivNoPadding" this.setCSSFromSelector("." + this.noPaddingClassName, { padding: "0px 10px" }) this.menu = new IconMenu({ layout: this, style: { backgroundColor : this.feedsBlueColor }}) //TODO: it would be cool to use variables with SVG, its quite simple. Just load the file into an "object" first - then manipulate it. OR have a processing step whitch takes the svg and inlines it. Then we can set the color+src at once. http://www.petercollingridge.co.uk/tutorials/svg/interactive/javascript/ this.menu.setContentData([ { link : { attributes: { title: "Main page" }, key: "page", value: "main", }, image: { src: "/img/white_logo_small.png" }, text: { html: "Main", className : "iconText" }}, { link : { attributes: { title: "Publisher information" }, key: "page", value: "publisher", }, image: { src: "/img/suitcase_blue.svg", var: "publisher_icon" }, text: { html: "Publishers", className : "iconText" }}, { link : { attributes: { title: "Help and F.A.Q" }, key: "page", value: "help", }, image: { src: "/img/help_blue.svg", var: "help_icon" }, text: { html: "Help", className : "iconText" }}, { link: { attributes: { title: "Account"}, key: "page", value: "account" }, image: { src: "/img/user_circle.svg", var: "user_circle" }, text: { html: "Account", className : "iconText" }} ]) //we have removed scrollToTop: 1 //old privacy icon: { link : { attributes: { title: "Read the privacy policy" }, key: "page", value: "privacy", }, image: { src: "/img/privacy_blue.svg", var: "privacy_icon" }, text: { html: "Privacy", className : "iconText" }} //we can do this when we have time to learn how to center the transformed image //this.setCSSFromSelector(".feedsIconMenuTransform", { transform : "matrix3d(0.9781476007338057, 0, -0.20791169081775931, 0, 0, 1, 0, 0, 0.20791169081775931, 0, 0.9781476007338057, 0, 20, 0, 0, 1)", "transform-origin" : "center left", width : "100px" }) //this.setCSSFromSelector(".feedsIconMenuTransform", { transform : "translateX(25%) rotateY(12deg)", "transform-origin" : "center left", width : "100px" }) //this.setCSSFromSelector(".feedsIconTransform", { transform : "rotateY(0deg) translateX(45%)", "transform-origin" : "center" }) //setup components this.pages = { "invoices": { component: "InvoicesPage", autoURL: "/js/invoicesPage.js" }, "account": { component: "AccountPage", autoURL: "/js/accountPage.js" }, "linkGenerate": { component: "LinkGenerate", autoURL: "/main/linkGenerate.js" }, "topList": { component: "TopListPage", autoURL: "/utilities/topListPage.js" }, } } AggressiveLayout.prototype.siteComponentOld = function(variable, siteComponent) { if (!this[variable]) { this[variable] = new siteComponent(this); this[variable].setupFunction(); } return this[variable]; } AggressiveLayout.prototype.anchorChangeCallback = function(event, actions) { if (actions && actions.page) { this.page = actions.page; } else this.page = "main" var currentPage = this.pages[this.page] if (currentPage) { //let components get a chance to respond to anchorChanges this.siteComponent(this.page, currentPage, "anchorChangeCallback", arguments) } } AggressiveLayout.prototype.layoutFunction = function() { //first the menu before calling components this.menu.markSelected(this.page) var json = [ this.menu.templateJSON(), //this.loginMenu.templateJSON(),hej? { type: "noscript", text: "#Please turn on javascript!\n\nThis page works best with JS, it has no ads or tracking."}, { var : "mainPageDiv", hasChildren : 1 } ] this.layoutJSON(this.elements.rootElement, json) //then build the pages var currentPage = this.pages[this.page] if (currentPage) { //if (!currentPage.layoutFunction) this.siteComponent(this.page, currentPage, "layoutFunction", [this.elements.mainPageDiv]) return } switch (this.page) { case 'invoices': console.log("error!! no " + this.page); break; case "privacy": this.siteComponentOld("privacyPage", PrivacyPage).layoutFunction(this.elements.mainPageDiv); break; case "account": //this.siteComponentOld("accountPage", AccountPage).layoutFunction(this.elements.mainPageDiv); console.log("another error account!"); break; case "help": this.siteComponentOld("helpPage", HelpPage).layoutFunction(this.elements.mainPageDiv); break; case "publisher": this.siteComponentOld("publisherPage", PublisherPage).layoutFunction(this.elements.mainPageDiv); break; case "login": case "signup": this.layoutLogin(); break; case "logout": this.layoutLogout() case "main": default: this.layoutMain(); } } AggressiveLayout.prototype.layoutLogout = function() { if (!this.isLoggingOut) { this.isLoggingOut = 1 this.loginAPI.logout() } var content = [ { text: "logging out..."} ] this.template.setContentData(content); this.layoutJSON(this.elements.mainPageDiv, this.template.templateJSON()) } AggressiveLayout.prototype.didLogout = function() { this.modifyAnchor("page", null, "#") } AggressiveLayout.prototype.layoutMain = function() { var cardChildren = [ { symbol: "📖", title: "Add any source", body: "Websites are turned into a feed, straight from the web or via RSS (with full text articles).\n\nSupports almost any website on the net, and greater support is added continuously" }, { symbol: "🧠", title: "AI categories", body: "The app learns what **you** like and promotes what you usually read, using on-device (private) machine learning AI.\n\nTo save your precious time!" }, { symbol: "📱", title: "Widget", body: "Widget on your homescreen with the most interesting articles" }, { symbol: "🚀", title: "Push", body: "Pushes the most important news on a daily basis, as a subtle notification" }, { symbol: "💥", title: "Updates", body: "The app keeps track of what's new, and gives you the new articles in a convenient feed-form." }, { symbol: "🙊", title: "Mute topics", body: "Mark words or phrases to hide posts. They are still included in the feed - just one tap away"}, { symbol: "🥰", title: "Easy to use", body: "Add websites straight from the browser - or any other app. No need to \"get into RSS\" or \"setting up accounts\" - just add what you like, it could not be any simpler!" }, { symbol: "🤘", title: "Human friendly", body: "No folders to move around, categories to select and reorder, marking items as read, or other chores to perform - just a beautiful feed containing your interest.\n\nThe machine does the work!" }, { symbol: "💵", title: "Free to download", body: "The app is a **free download!** with most features included and you can unlock the full experience for a small fee. If you share Feeds with your friends, you will even be rewarded an unlock for free!" }, ] //{ image: "/img/help.png", title: "AI categories", body: }, //{ html: "* Also very cute!" }, //{ html: "**Free to download!** Utilizing the supercomputer in your pocket there is no need to sign up for additional services, powered by a super-smart download-algorithm." }, //**INTRODUCING: Natural scrolling**! You read naturally from top to bottom where new unread posts always comes in from below - you will never again scroll down to read and then go back up to refresh, then scroll down again to find what's new like a little detective. **Just keep on reading**, a streamlined laser-focused feed reader just for you.\n\n\ for (var index = 0; index < cardChildren.length; index++) { var item = cardChildren[index]; var image = { className: "cardChildImage" } if (item.image) { image.autoType = AUTO_TYPE.image image.src = item.image } else { image.html = item.symbol || "F" } var card = { className: "cardChild", children: [ image, { type: "h2", html: item.title }, { text: item.body }, ]} cardChildren[index] = card } var content = [ { parentClassName: this.noPaddingClassName, style : { padding: "0px"}, children: [ { className : "icon_container", children : [{ className: "floatingLogo", autoType : AUTO_TYPE.image, src : "img/pitchImage.jpg", alt : "Photo by Christina @ wocintechchat.com on Unsplash" }]}, { children: [ { style : { padding: "5px 0px 0px 5px"}, text: this.textTagLine }, { style: { padding: "10px", textAlign: "center", display: "block"}, type: "a", href: this.appstoreLink, children: [ { style: { borderColor : "white" }, autoType: AUTO_TYPE.button, plain: 1, html: "Download" } ]} ] }, { style : { clear : "both"}} ]}, { templateSkip: 1, style: { paddingTop: "1em"}, children: [ { type: "h1", html: "Powerful and friendly!", className: "centered" }, { className: "cardContainer", children: cardChildren }, ]}, //text: "#AI - Machine learned categories\n\nFeeds learns what you like and automatically categorizes articles into levels of interest. This makes reading faster since you only need to skim the top, and when there is more time, you can scroll further. All done on-device, keeping your privacy." { children: [ { text: "#What do people say about Feeds?" }, { text: "”It is the only news app I have time for, it has both my news and the Journal of Medicine so I don't need to check several places for updates” – *Hanna Schiöler MD*" }, { text: "”I like the nice Feeds app. It’s the only one I found with a working widget” – *Mathias Buchner*" }, { text: "”I am so happy about Feeds! It's such a nice app!” – *Petra Sjöström*" }, ]}, { className: "videoHolder", children: [ { className: "videoChild", children: [ { html: "Turn almost any website into a feed:"}, { type: "video", attributes: { controls: "1", playsinline: true, preload: "none", poster: "/img/vid_poster.png" }, children: [ { type: "source", attributes: { src: "/img/AddSearch.mp4", type:"video/mp4" }} ]}, { style: { fontSize: "small" }, html: "Keep track of the net, like google seaches!" }, ]}, { className: "videoChild", children: [ { html: "Add feeds straight from the browser:"}, { type: "video", attributes: { controls: "1", playsinline: true, preload: "none", poster: "/img/vid_poster.png" }, children: [ { type: "source", attributes: { src: "/img/AddAFeed.mp4", type:"video/mp4" }} ]}, { style: { fontSize: "small" }, html: "Can it get any easier?" }, ]} ]}, { style: { paddingTop: "10px"}, children: [ { text: "#New version out now!\n\n\ Numerous improvements: \n\n\ * An on-device AI that learns what you like and saves you time by bringing the best first!\n\n\ * Supports even more sites when generating feeds from the web (siteFeeds)\n\n\ * Homescreen Widget for the newest and most interesting articles!\n\n\ * Push-notifications (once or twice per day), for the most interesting stuff!\n\n\ * Better price! If you rather pay once and get all these features for life - you are now accommodated!\n\n\ * Also a little friendlier and better looking - always improving on that front\n\n\ * Future releases will come more often and be smaller updates\n\n\ » [Download and be ready when it hits the shelves!](" + this.appstoreLink + ")" }, { text: "#Get the app for free\n\n\ Don't like paying for things when you don't have to?\n\n\ The new version rewards you with a subscription (or extends the current one) every time a friend of yours downloads the app.\n\n\ You can also share regular links via the Feeds-app, and if your friends (or whoever receives them) aren't interested in the app they can still read the link, and the others give you the subscription - everybody wins!\ "}, { type: "span", html: "» "}, { autoType: AUTO_TYPE.anchorLink, html : "Signup to Feeds", key: "page", value: "login" } ]}, { children: [ { text: "#First look\n\nHere is a video from the first version of the app, of how scrolling and refreshing works:"}, { type: "video", attributes: { controls: "1", loop:true, playsinline: true, preload: "none", autoPlay: true }, children: [ { type: "source", attributes: { src: "/img/NaturalScrolling.mp4", type:"video/mp4" }} ]}, { text: "Interested in the details? I wrote something about the design of this feature: [laser focused app](https://aggressive.se/blog/#post_url=laser-focusednbspapp)" }, ]}, { style: { height: "150px"}}, ] this.template.setContentData(content); this.layoutJSON(this.elements.mainPageDiv, this.template.templateJSON()) //this.layoutJSON(this.elements.mainPageDiv, content) } AggressiveLayout.prototype.didLogin = function(loginBool) { if (!loginBool) { //why and what? this.modifyAnchor("page", "login", "#") } this.updateLayout(); } AggressiveLayout.prototype.didVerify = function() { if (!this.layout.accountData) this.layout.accountData = {} this.layout.accountData.account_status |= 1 }; AggressiveLayout.prototype.layoutLogin = function() { var privacyOrLoggedIn; if (this.login_token) { privacyOrLoggedIn = { children: [ { text : "You are logged in!\n\n❤️ ❤️ Thanks for signing up! ❤️ ❤️", style : { textAlign : "center" }}, { text: "Make sure to check your email (especially the spam filter) to verify the account" }, ]}; } else { this.loginAPI.first_create_account_text = "#Sign up!\n\nTo get Feeds at a discount:" privacyOrLoggedIn = { children : [ { children: this.loginAPI.layoutJSONData }, { type: "p" }, ]} } var content = [ { parentClassName: this.noPaddingClassName, style : { padding: "0px"}, children: [ { className : "icon_container", children : [{ className: "floatingLogo", autoType : AUTO_TYPE.image, src : "img/index_reading.jpg", alt : "Photo of a clouded sky by Daniel Pascoa on Unsplash" }]}, { style : { padding: "5px 0px 0px 5px"}, text: this.textTagLine }, { style : { clear : "both"}} ]}, privacyOrLoggedIn, { style: { paddingTop: "10px"}, text: "#Open Beta\n\nFeeds has currently a public beta for everyone to join:\n\n [Testflight-beta program](https://testflight.apple.com/join/YBFNq1bw)"} ] this.template.setContentData(content); this.layoutJSON(this.elements.mainPageDiv, this.template.templateJSON()) } //AggressiveLayout.prototype.scrollToDiv = function(event, divName) moved to feedsDefault! ///Callback for unsuccessful requests AggressiveLayout.prototype.errorCallback = function(payload, request) { this.handlePlugins("errorCallback", [payload, request]); }