Giter VIP home page Giter VIP logo

django-oscar-stores's Introduction

image

Domain-driven e-commerce for Django

Oscar is an e-commerce framework for Django designed for building domain-driven sites. It is structured such that any part of the core functionality can be customised to suit the needs of your project. This allows a wide range of e-commerce requirements to be handled, from large-scale B2C sites to complex B2B sites rich in domain-specific business logic.

Contents:

local

image

image

Further reading:

Continuous integration status:

image

Coverage

Requirements Status

PyPI status:

image

Docs status:

Documentation Status

Core team:

Supported versions

The currently supported versions of Oscar are:

Version End of support
3.2 LTS January 2026
3.1 April 2022
3.0 May 2021
2.2 LTS August 2023

Supported versions are eligible for fixes for data loss bugs and security issues. Releases designated as Long-term support (LTS) releases will receive support for an extended period of 3 years from their release date.

Screenshots

Sandbox

These are screenshots from the 'sandbox' example site that ships with Oscar. It sports a simple design built with Twitter's Bootstrap and provides a good starting point for rapidly building elegant e-commerce sites.

image

image

image

image

The sandbox site is also available to browse at https://latest.oscarcommerce.com.

The sandbox site can be set-up locally in 5 commands. Want to make changes? Check out the contributing guidelines.

Extensions

The following extensions are stable and ready for use:

The following are community-written extensions:

Let us know if you're writing a new one!

Videos

Videos with talks about Oscar:

License

Oscar is released under the permissive New BSD license (see summary).

Contributing to the Project

We welcome contributions to the project! Whether it's a bug fix, a new feature, or just some documentation improvements, your contributions are greatly appreciated.

To contribute, please follow these steps:

Fork the project repository on GitHub. Clone your forked repository to your local machine. Create a new branch for your changes. Make your changes, and commit them with clear commit messages. Push your changes to your forked repository. Open a pull request on the original project repository, explaining your changes. Please note that all contributions are subject to review, and may be modified or rejected if they do not meet the project's standards.

Code of Conduct

We want everyone involved in the project to feel safe and respected, regardless of their background or identity. As such, we have adopted the following Code of Conduct:

Our Pledge

In the interest of fostering an open and welcoming environment, we pledge to:

Be friendly and welcoming to all contributors. Respect differing viewpoints and experiences. Accept constructive criticism and feedback graciously. Focus on what is best for the community and the project.

Our Standards

We expect all contributors to:

Use welcoming and inclusive language. Be respectful of differing viewpoints and experiences. Gracefully accept constructive criticism. Focus on what is best for the community and the project.

Our Responsibilities

Project maintainers are responsible for:

Enforcing the Code of Conduct. Investigating and addressing reported violations of the Code of Conduct. Making clear and fair decisions about disciplinary actions for violations of the Code of Conduct. Scope This Code of Conduct applies to all contributors, both online and offline, in all project spaces, including but not limited to project forums, mailing lists, GitHub repositories, and in-person events.

Enforcement

If you witness or experience unacceptable behavior, or have any other concerns, please notify the project maintainers at [email protected] & [email protected]. All reports will be kept confidential, and the project maintainers will work with you to determine a resolution.

We reserve the right to take any action deemed necessary to enforce this Code of Conduct, including but not limited to warning the offender, banning the offender from the project's spaces, or reporting the offender to relevant authorities. Case studies ------------

Oscar is still in active development but is used in production by a range of companies, from large multinationals to small, boutique stores. See http://oscarcommerce.com/cases.html for an overview.

Many more on the way. If you use Oscar in production, please let us know.

Looking for commercial support?

If you are interested in having an Oscar project built for you, or for development of an existing Oscar site then please get in touch via [email protected].

django-oscar-stores's People

Contributors

alexmet avatar b4isty avatar codeinthehole avatar dependabot-preview[bot] avatar dependabot[bot] avatar diegox80 avatar fmr avatar izidormatusov avatar jayvdb avatar jwayodi avatar maiksprenger avatar mvantellingen avatar oliverrandell avatar richardhewett avatar solarissmoke avatar tangent-deployment avatar v1kku avatar zuck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-oscar-stores's Issues

Change store's ``location`` field to be mandatory (``NOT NULL``)

Using MySQL does not support NULL columns when using spatial indexes. In addition, spatial indexes are not supported when using InnoDB. There are 3 ways to work around this:

  1. set the spatial_index option for the field to False which will have a negative impact on all database backends.

  2. Make the field mandatory, i.e. NOT NULL. This is not really an issue in this specific instance because we have a map widget available that makes it easy to specify a location for the store.

  3. Describe in the docs that this is an issue and how to work around it if someone really wants to use MySQL with GIS...it should be discouraged though!

I think the most sensible solution is 2). Thoughts and additional suggestions are appreciated!

Optionally link stores to partners

I would like to optionally link stores to specific partners, where partners are part of a network offering both physical stores and delivery fulfillment.

Currently the stores data model has separate inventory control, but in this scenario the physical store inventory is effectively shared between online and physical purchases. The Oscar partner component already provides inventory control, and it is undesirable to duplicate it for the stores component.

IMO it would make sense for stores to always link to an oscar partner, allowing that component to handle access control and inventory control. Existing data could be migrated by creating new partner records for the existing stores. However that would make typically mean the offline stock would become online stock, which wouldnt be suitable for most sites. I propose migrating by creating product variants for each store, which can be optionally linked to the Partner, and product variants offer seemingly equivalent stock control as the stores component. Product variants can be marked as not "Is public" in order to remove them from the core online purchase search and catalogue, so those product variants could be visible only in stores component. The one field in StoreStock which doesnt have a suitable mapping to Partner and Product variants is StoreStock.location. I'm still looking into how that might fit into a revised model.

Map not displayed on diplaying on store page with missing location data

On the store detail page, the map with the stores location is not showing up if the store has no location set. That means that the space taken up by the map is blank. That's not the way it is supposed to be. Two ways to handle this situation gracefully:

  1. Hide the whole map when no location coordinates are available.

  2. Display the map properly but don't try to display a marker in the javascript for a non-existing location.

What do you think is the best solution for this?

[Question] Adding to front page

Hi, this is working great! I would like to add it to my home page (Promotion box). Should I just change the template similar to nav_primary.html?

Cheers, Mykl

Django returns status 500 instead of 404 in some cases

Issue Summary

As described in the title, Django return 500 instead of 404 when trying to hit specific urls that do not exist.

Steps to reproduce

Hit the following url: http://localhost:8000/en/stores/asdf/1/ , where 'asdf' can be anything and '1' can be any legal store_id.
A status 500 will appear instead of 404 since this is not an existing url.

Technical Details

  • Python: 3.5.9
  • Django==2.1.5
  • django-oscar==2.0.1
  • django-oscar-stores==2.0
  • ubuntu 20.04

Additional Details

  1. The status 500 remains when replacing 'asfd' with anything.
  2. Django returns 404 when replacing 'asdf' with nothing. i.e http://localhost:8000/en/stores/1/
  3. Django returns 404 when replacing store_id with some non existent.
  4. Django returns 404 in any other case.

Quick fix

I exclude the following block of code to be returned in the urlpatterns.

url(r'^(?P<dummyslug>[\w-]+)/(?P<pk>\d+)/$',
                self.detail_view.as_view(), name='detail'),

I know this is not a permanent solution to the problem.
From my experience, I guess, it has something to do with the 'detail_view' above.

Traceback

https://dpaste.com/6W34EMQG5.txt

Is this a typo in extrascripts.html?

Issue Summary

I came across the following block of code:

if (typeof gettext === 'undefined') {
    jQuery.getScript('{% url 'javascript-catalogue' %}');
}

which is located at stores/templates/stores/partials/extrascripts.html.

Is the url above related to Django translation url?

path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),

If yes, shouldn't it be {% url 'javascript-catalog' %};?
if not, what is its purpose for?

Source: https://docs.djangoproject.com/en/2.2/topics/i18n/translation/#module-django.views.i18n

[Question] Installation Oscar Sandbox ver 1.3

Hi, I want to add this to Oscar Sandbox which is Oscar ver 1.3 I have to look at. I noticed that the requirements in Stores are previous versions than in Oscar.

I guess my questions are

  1. Can I install this in the Sandbox?
  2. Do I need to modify the requirements??
  3. If yes, should I do make sandbox like I did for Oscar?
  4. If no, what do I need to do to get it installed?

cheers

Sandbox doesn't use Oscar CSS

This is caused by an upstream change in Oscar around the use of Less and CSS. Oscar's base.html template currently only specifies the Less files and relies on the pre-processors being defined in our settings.py to work.

This isn't the case for the sandbox by default.

The Less/CSS thing is still under discussion in Oscar and so it's not immediately clear what to do about this at this moment.

REST API

I need a REST api for stores. Should I attempt to build it into this project, or as a separate project?

Review javascript

Tasks:

  • Use auto-exec closure style?
  • Review the default lat/lng
  • Move all event binding to templates
  • Detail page JS needs encapsulating
  • Dashboard page JS needs encapsulating
  • getGeoJsonFromGeo... shouldn't return a default.

Setting SPATIALITE_LIBRARY_PATH in sandbox/settings.py causes problems in Ubuntu

It seems that setting SPATIALITE_LIBRARY_PATH in the sandbox settings [1] file causes problems for me when trying to run the sandbox. It overrides my local setup and breaks.

Is it possible to remove this from the settings file? Is it just the SPATIALITE_LIBRARY_PATH that needs to be set for you to get it to work? You could move that into the postactivate script of the virtualenv for the project. Would that work?

[1] Line 212 in sandbox/sandbox/settings.py

store_stock template tag only works for PostGIS

GeoDjango's queryset API allows for specifying a field_name that should be used for the specific method used. The keyword is, however, limited to fields on the same model itself.

According to the documentation PostGIS is the only backend that supports calculations on related models such as: stores__location. This currently limits the template tag to be only usable with PostGIS.

This need to be solved. Ideally with a solution that works for every backend although it might be better to leverage the PostGIS internal handling on that backend and have a fallback for others.

StoreStock and Pricing

Why doesn't the StoreStock model have a price field? Is it left out intentionally?

Also, I think it would be a good idea to extend Oscar's StockRecord model. The only downside would be that the field name has to be partner even though it'll be referring to a Store. Something like this:

class StoreStock(AbstractStockRecord):
    partner = models.ForeignKey('stores.Store', ...)

README and Django 2+

The README link to geoip (https://docs.djangoproject.com/en/stable/ref/contrib/gis/geoip/) is a 404, because the default version now uses geoip2.
The two links which work are
https://docs.djangoproject.com/en/1.10/ref/contrib/gis/geoip/
https://docs.djangoproject.com/en/stable/ref/contrib/gis/geoip2/

Also the README urls.py example uses url(..) instead of path(..) or similar.
oscar and oscar-api show both Django 1 and Django 2
e.g. https://django-oscar-api.readthedocs.io/en/latest/usage/outofthebox.html#use-oscar-api-out-of-the-box

From CI I can see that most things work on Django 2, so I fiddled for a bit and I wasnt able to use path(..).

This

path('stores/', apps.get_app_config('stores').get_urls()),

results in

File ".../django/urls/conf.py", line 61, in _path
    urlconf_module, app_name, namespace = view
ValueError: not enough values to unpack (expected 3, got 2)

And apps.get_app_config('stores_dashboard') results in

LookupError: No installed app with label 'stores_dashboard'.

Does not work with Python3.3

I am attaching the debug panel info

Request Method: GET
Request URL: http://127.0.0.1:8000/dashboard/stores/create/
Django Version: 1.7.1
Exception Type: NameError
Exception Value:
global name 'unicode' is not defined
Exception Location: /Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/stores/dashboard/forms.py in get_weekday_display, line 140
Python Executable: /Users/sandeepgoje/.virtualenvs/kirana3/bin/python
Python Version: 3.3.6
Python Path:
['/Users/sandeepgoje/Work/kirana/kirana/django-oscar/sites/demo',
'/Users/sandeepgoje/Work/kirana/kirana/django-oscar',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/django_tables2-0.15.0-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/factory_boy-2.4.1-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/mock-1.0.1-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/phonenumbers-6.3.0-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/purl-1.0.3-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/Unidecode-0.04.17-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/django_compressor-1.4-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/Babel-1.3-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/sorl_thumbnail-11.12.1b-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/django_treebeard-2.0-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/django_haystack-2.3.1-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/django_extra_views-0.6.4-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/Pillow-2.4.0-py3.3-macosx-10.10-x86_64.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/django_appconf-0.6-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/pytz-2014.10-py3.3.egg',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python33.zip',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/plat-darwin',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/lib-dynload',
'/opt/local/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3',
'/opt/local/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/plat-darwin',
'/Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages']

Error during template rendering

In template /Users/sandeepgoje/.virtualenvs/kirana3/lib/python3.3/site-packages/stores/templates/stores/dashboard/store_update.html, error at line 134
global name 'unicode' is not defined
124 {% for formset in workhours %}
125 {% if formset.non_field_errors %}
126 {% for error in formset.non_field_errors %}
127


128 {{ error }}
129

130 {% endfor %}
131 {% endif %}
132

133

134 {{ formset.get_weekday_display }}
135

136
137

138 {{ formset.open.label }}
139 {{ formset.open }}
140

141
142

143
144

Error in documentation on url portion

URL for javascript internationalization has missing url function.
Now it's
(r'^jsi18n/$', JavaScriptCatalog.as_view(), name="javascript-catalogue"),

It will be
url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name="javascript-catalogue"),

how to fork order apps in oscar?

Hi

I have the issue below when I try to fork oscar.order application. I don't have any problem when I fork other applications such as checkout, shiipping etc. Can you tell me what is the proper way to fork order applications?

ERRORS:
payment.Source.order: (fields.E300) Field defines a relation with model 'order.Order', which is either not installed, or is abstract.
voucher.VoucherApplication.order: (fields.E300) Field defines a relation with model 'order.Order', which is either not installed, or is abstract.

Thanks,
Kah Fai

Drop support for Oscar 0.5

A new release should drop support for Oscar 0.5. Then we can:

  • Stop using Oscar test support
  • Add a link to stores in the sandbox nav

AddressNotFoundError at /dashboard/stores/create/

When creating the first new store, we see

The address 127.0.0.1 is not in the database.

I can create a store in /admin , and the view & edit it normally in the dashboard.

GeoIP is set up, but I havent separately verified it is working. Likewise I havent independently verified Google or spatialite are operational.

Whatever is going on, address "127.0.0.1" is illogical.

django-oscar-views version conflict

Oscar 0.4 required django-extra-views>=0.2.4 (but <0.3)
This extension requires version 0.5.2

This conflict causes some pain on install and may prevent automated installation

looking to modify package for use with Django 1.10.7

Hi, I've just installed this on Python 3.5 and Django 1.10.7. Obviously it hasn't been upgraded to 1.10.7 but I started looking through the code and fixing things. I've fixed a lot of the deprecated code and have several parts of the app working. I hit a wall with stores/dashboard/forms.py line 137.

fk = [f for f in OpeningPeriod._meta.fields if f.name == 'store'][0]

It returns an error 'function' object has no attribute '_meta'

_meta.fields has been deprecated and should now be _meta.get_fields()

from django import forms
from django.forms import models as modelforms
from django.db.models import Q
from django.contrib.gis.forms import fields
from django.utils.translation import ugettext_lazy as _
from django.contrib.gis.geoip2 import HAS_GEOIP2
from django.conf import settings
from django.apps import apps

OpeningPeriod = apps.get_model('stores', 'OpeningPeriod')
assert OpeningPeriod


class StoreAddressForm(forms.ModelForm):

    class Meta:
        model = apps.get_model('stores', 'StoreAddress')
        exclude = ('title', 'first_name', 'last_name', 'search_text')


class StoreForm(forms.ModelForm):
    location = fields.GeometryField(widget=forms.HiddenInput())

    class Meta:
        model = apps.get_model('stores', 'Store')
        exclude = ('slug', 'opening_periods', )
        widgets = {
            'description': forms.Textarea(attrs={'cols': 40, 'rows': 10}),
        }

    def __init__(self, *args, **kwargs):
        current_ip = kwargs.pop('current_ip', None)
        super(StoreForm, self).__init__(*args, **kwargs)

        # Make sure that we store the initial data as GeoJSON so that
        # it is easier for us to use it in Javascript.
        instance = kwargs.get('instance', None)
        if instance:
            self.initial['location'] = instance.location.geojson
        elif HAS_GEOIP2 and getattr(settings, 'GEOIP_ENABLED', True):
            from django.contrib.gis.geoip2 import GeoIP2
            point = GeoIP2().geos(current_ip)
            if point:
                self.initial['location'] = point.geojson

    def clean_reference(self):
        ref = self.cleaned_data['reference']
        if ref == "":
            return None
        return ref


class OpeningPeriodForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(OpeningPeriodForm, self).__init__(*args, **kwargs)
        time_input = ['%H:%M', '%H', '%I:%M%p', '%I%p', '%I:%M %p', '%I %p']
        self.fields['start'].input_formats = time_input
        self.fields['start'].required = False
        self.fields['end'].input_formats = time_input
        self.fields['end'].required = False

    class Meta:
        model = OpeningPeriod
        exclude = ('store', 'weekday', )
        widgets = {
            'name': forms.TextInput(
                attrs={'placeholder': _("e.g. Christmas")}
            ),
            'start': forms.TimeInput(
                format='%H:%M',
                attrs={'placeholder': _("e.g. 9 AM, 11:30, etc.")}
            ),
            'end': forms.TimeInput(
                format='%H:%M',
                attrs={'placeholder': _("e.g. 5 PM, 18:30, etc.")}
            ),
        }


class DashboardStoreSearchForm(forms.Form):
    name = forms.CharField(label=_('Store name'), required=False)
    address = forms.CharField(label=_('Address'), required=False)

    def is_empty(self):
        d = getattr(self, 'cleaned_data', {})
        empty = lambda key: not d.get(key, None)
        return empty('name') and empty('address')

    def apply_address_filter(self, qs, value):
        words = value.replace(',', ' ').split()
        q = [Q(address__search_text__icontains=word) for word in words]
        return qs.filter(*q)

    def apply_name_filter(self, qs, value):
        return qs.filter(name__icontains=value)

    def apply_filters(self, qs):
        for key, value in self.cleaned_data.items():
            if value:
                qs = getattr(self, 'apply_%s_filter' % key)(qs, value)
        return qs


class IsOpenForm(forms.Form):
    open = forms.BooleanField(label=_('Open'), required=False)

    def __nonzero__(self):
        self.is_valid()
        return self.cleaned_data['open']


class OpeningPeriodFormset(modelforms.BaseInlineFormSet):
    extra = 10
    can_order = False
    can_delete = True
    min_num = 0
    max_num = 30 # Reasonably safe number of maximum period intervals per day
    absolute_max = 30
    model = apps.get_model('stores', 'OpeningPeriod')

    #This didn't work either   fk = [f for f in OpeningPeriod.get_fields() if f.name == 'store'][0]

    fk = [f for f in model._meta.get_fields() if f.name == 'store'][0]

    validate_min = True
    validate_max = True

    def __init__(self, weekday, data, instance):
        self.weekday = weekday
        if instance:
            queryset = instance.opening_periods.all().filter(weekday=weekday)
        else:
            queryset = OpeningPeriod.objects.none()
        prefix = 'day-%d' % weekday

        self.openform = IsOpenForm(data=data or None, prefix=prefix, initial={
            'open': len(queryset) > 0
        })

        self.open = self.openform['open']

        super(OpeningPeriodFormset, self).__init__(data=data, instance=instance,
                                                   prefix=prefix,
                                                   queryset=queryset)

    def get_weekday_display(self):
        return unicode(OpeningPeriod.WEEK_DAYS[self.weekday])

    def form(self, *args, **kwargs):
         form = OpeningPeriodForm(*args, **kwargs)
         form.instance.weekday = self.weekday
         form.instance.store = self.instance
         return form

    def is_valid(self):
        return super(OpeningPeriodFormset, self).is_valid()

    def save(self, *args, **kwargs):
        if not self.openform:
            for form in self:
                if form.instance.pk:
                    form.instance.delete()
        else:
            return super(OpeningPeriodFormset, self).save(*args, **kwargs)


class OpeningHoursFormset(object):
    def __init__(self, data, instance):
        self.data = data or None
        self.instance = instance
        self.forms = [self.construct_sub_formset(weekday) for weekday in
                      OpeningPeriod.WEEK_DAYS]

    def __iter__(self):
        return iter(self.forms)

    def __getitem__(self, key):
        return self.forms[key]

    def construct_sub_formset(self, weekday):
        return **OpeningPeriodFormset(
            weekday,
            self.data or None,
            self.instance,**
        )

    def is_valid(self):
        return all([form.is_valid() for form in self.forms])

    def save(self):
        for form in self:
            form.save()


class OpeningHoursInline(object):
    def __init__(self, model, request, instance, kwargs=None, view=None):
        self.data = request.POST
        self.instance = instance

    def construct_formset(self):
        return OpeningHoursFormset(
            self.data or None,
            self.instance,
        )

When I get this finished, I'll post the fork.
Cheers, Mykl

Search results page could be clearer

image

It's not really clear that it is a search results page as you have items in the left-hand sidebar and in the main content area. Better to consolidate and show the distance more prominently.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.