DAB0mB / Appfairy

A CLI tool to Migrate a Webflow project into a React app
MIT License
287 stars 39 forks source link

Interactions and observers not working with appfairy #7

Closed jayb967 closed 3 years ago

jayb967 commented 5 years ago

I wasn't able to see any of my js scripts run on my pages when I ran the appfairy command. It seems like the issue was that appfairy renames all classes on the html files with "af-class-yourclass" so then the js file cannot attach to those after.

A quick workaround, a little time consuming but works:

Just search for selectors on bottom of webflow js file and add "af-class-" to them. i.e. ".thisClass" to ".af-class-thisClass"

They are all within these 2 initializer functions at the bottom of the Webflow generated script: Webflow.require('ix').init(....)

Webflow.require('ix2').init(...)

Also, I don't know if its because I am rendering the pages on the server with NextJS, but I also had to add some attributes to my html tag for other animations to work correctly using: var doc = document.getElementsByTagName("html")[0] doc.setAttribute('data-wf-page', 'yourPageID') doc.setAttribute('data-wf-site', 'yourWebflowSiteID') //optional for language doc.setAttribute('lang', 'en')

Also, with nextJS I had to wrap these two initializer functions so they would only run on client side and not give me a "document not defined" when compiled on server using: $( document ).ready(function() {}

Hope this saves someone else a day of debugging!

DAB0mB commented 5 years ago

@jayb967 Appfairy renames the classes and for a good reason - it saves potential conflicts when attaching additional stylesheets, because Webflow uses extremely generic rules. Appfairy shouldn't rename elements which start with a w- prefix though, for that very reason. What classes do you have troubles with? Can you provide specific names?

jayb967 commented 5 years ago

Yes I understand the webflow class name change which is ok, but a lot of interactions made on webflow are not called on the html new class name "af-class-.." from the generated js file. For instance here is a small snippet of my webflow generated interaction inside my js folder, after using the appfairy command: { "slug": "reveal-navigation", "name": "Reveal Navigation", "value": { "style": {}, "triggers": [{ "type": "click", "selector": "<mark>.menu-content</mark>", "preserve3d": true, "stepsA": [{ "transition": "transform 500ms ease 0ms", "x": "25%", "y": "0px", "z": "0px" }], "stepsB": [] }, { "type": "click", "selector": ".reset-menu", "stepsA": [{ "display": "block" }], "stepsB": [] }] } }, { "slug": "close-navigation", "name": "Close Navigation", "value": { "style": {}, "triggers": [{ "type": "click", "selector": ".**menu-content**", "preserve3d": true, "stepsA": [{ "transition": "transform 500ms ease 0ms", "x": "0px", "y": "0px", "z": "0px" }], "stepsB": [] }, { "type": "click", "stepsA": [{ "display": "none" }], "stepsB": [] }] } }, { "slug": "move-right", "name": "Move right", "value": { "style": { "opacity": 0, "x": "0px", "y": "0px", "z": "0px" }, "triggers": [{ "type": "load", "preload": true, "stepsA": [{ "wait": 700, "opacity": 1, "transition": "opacity 500ms ease 0ms" }], "stepsB": [] }] } }, { "slug": "zoom-in", "name": "Zoom in", "value": { "style": {}, "triggers": [{ "type": "hover", "selector": ".**project-image**", "preserve3d": true, "stepsA": [{ "transition": "transform 1000ms ease-in-out 0ms", "scaleX": 1.08, "scaleY": 1.08, "scaleZ": 1 }], "stepsB": [{ "transition": "transform 600ms ease-out 0ms", "scaleX": 1, "scaleY": 1, "scaleZ": 1 }] }] } }, { "slug": "rollover", "name": "rollover", "value": { "style": { "opacity": 0, "x": "0px", "y": "0px", "z": "0px" }, "triggers": [{ "type": "hover", "selector": ".**project-rollover**", "preserve3d": true, "stepsA": [{ "opacity": 1, "transition": "transform 600ms ease-out 0ms, opacity 600ms ease-out 0ms", "x": "0px", "y": "0px", "z": "0px" }], "stepsB": [{ "opacity": 0, "transition": "opacity 600ms ease-out 0ms" }] }] } }, { "slug": "open-menu", "name": "Open Menu", "value": { "style": {}, "triggers": [{ "type": "click", "selector": ".**main-menu**", "preserve3d": true, "stepsA": [{ "display": "block", "opacity": 1, "transition": "transform 200 ease 0, opacity 200 ease 0", "x": "0px", "y": "0px", "z": "0px" }], "stepsB": [] }, { "type": "click", "selector": ".**hamburger**", "stepsA": [{ "display": "none", "opacity": 0, "transition": "opacity 200 ease 0" }], "stepsB": [] }, { "type": "click", "selector": ".**close**", "stepsA": [{ "wait": "250ms" }, { "display": "block", "opacity": 1, "transition": "opacity 200 ease 0" }], "stepsB": [] }] } },, All of my selectors are still the same name and not also changed to "af-class-classname"which then doesn't call functions (i.e. where my mouse hover displays an underline)

DAB0mB commented 5 years ago

I guess I'll add an option to disable encapsulation but I truly don't like how webflow assumes it's the only thing that matters...

mackbdev commented 5 years ago

How did this turn out?

constantinX commented 4 years ago

Hi, i also have this issue. Renamed classes according to your answers, yet still not working. I think this tool can be really amazing if these issues are resolved.

ronaldocpontes commented 4 years ago

Hi I am having the same issue. @DAB0mB Do we have an option to disable encapsulation / renaming of the classes?

This is an example of a webflow site with animations that won't work on Appfairy:

https://webflow.com/website/Scholr-Education-One-Page

ronaldocpontes commented 4 years ago

Thanks for your tips @jayb967

I've created the following script to convert the json events inside Webflow.require('ix2').init(...):

const fs = require('fs');

let rawdata = fs.readFileSync('events.json');
let events = JSON.parse(rawdata);

function traverse(object, convertFunction) {
    if (typeof convertFunction != "function")
        throw "convertFunction must be a function(key,valye) that returns a value for all keys"

    if (object !== null && typeof object == "object") {
        Object.entries(object).forEach(([key, value]) => {
            object[key] = convertFunction(key, value)
            traverse(value, convertFunction);
        });
    }
}

traverse(events, (key, value) => (key == "selector") ? value.split('.').join('.af-class-') : value)

fs.writeFileSync('appfairy-events.json', JSON.stringify(events))

I had also to modify my index.js file to look like this:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';
import './scripts'
import './styles'
import IndexView from './views/IndexView'

// Run the following commands on the console from a deployed webflow site:
// document.getElementsByTagName("html")[0].getAttribute('data-wf-page')
// document.getElementsByTagName("html")[0].getAttribute('data-wf-site')

const WEBFLOW_PAGE_ID = 'your page id'
const WEBFLOW_SITE_ID = 'your site id'

class App extends React.Component {

  componentDidMount() {
    var doc = document.getElementsByTagName("html")[0]
    doc.setAttribute('data-wf-page', WEBFLOW_PAGE_ID)
    doc.setAttribute('data-wf-site', WEBFLOW_SITE_ID)
  };

  render() {
    return (
      <React.StrictMode>
        <IndexView />
      </React.StrictMode>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root'),
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

@DAB0mB Any chances of incorporating the above in Appfairy?

Ruborcalor commented 4 years ago

Wow thanks for writing Appfairy @DAB0mB and thanks for the tips @ronaldocpontes @jayb967!

I wrote up a summary of what I learned while facing these issues here.

Here is a little bash script that automates the application of the node script ronaldocpontes wrote:

#!/usr/bin/env bash

# Save json from webflow.js to events.json
tail -n2 webflow.js | head -n1 > events.json

# Delete last two lines of webflow.js
sed -i '$ d' webflow.js
sed -i '$ d' webflow.js

# Generate appfairy-events.json
node converter.js

# Write appfairy-events.json to webflow.js
cat appfairy-events.json >> webflow.js

# Add closing parenthesis
echo >> webflow.js
echo ");" >> webflow.js

Also if someone is facing issues with on page load interactions, I think it's a problem with Webflow -> React, not Appfairy. My work around was to make it an onclick animation, assign the click to a button with display: none, and then trigger the click of that button from useEffect/componentDidMount.

document.getElementById("animation-button").click();
DAB0mB commented 3 years ago

I've added native support for that in version 0.8.0. It will work out of the box now