diff --git a/mediagoblin/static/images/icon_collect.png b/mediagoblin/static/images/icon_collect.png
new file mode 100644
index 00000000..2911af24
Binary files /dev/null and b/mediagoblin/static/images/icon_collect.png differ
diff --git a/mediagoblin/static/js/collection_form_show.js b/mediagoblin/static/js/collection_form_show.js
new file mode 100644
index 00000000..03a4906b
--- /dev/null
+++ b/mediagoblin/static/js/collection_form_show.js
@@ -0,0 +1,26 @@
+/**
+ * GNU MediaGoblin -- federated, autonomous media hosting
+ * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+$(document).ready(function(){
+ $('#new_collection').hide();
+ $('#button_addcollection').click(function(){
+ $('#new_collection').slideToggle('fast', function(){
+ $('#collection_title').focus();
+ });
+ });
+});
diff --git a/mediagoblin/templates/mediagoblin/edit/edit_collection.html b/mediagoblin/templates/mediagoblin/edit/edit_collection.html
new file mode 100644
index 00000000..5cf5bae8
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/edit/edit_collection.html
@@ -0,0 +1,39 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block mediagoblin_content %}
+
+
+
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/listings/collection.html b/mediagoblin/templates/mediagoblin/listings/collection.html
new file mode 100644
index 00000000..4d502201
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/listings/collection.html
@@ -0,0 +1,43 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% from "mediagoblin/utils/object_gallery.html" import object_gallery %}
+
+{% block mediagoblin_head %}
+
+{% endblock mediagoblin_head %}
+
+{% block title %}
+ {% trans %}Media tagged with: {{ tag_name }}{% endtrans %} — {{ super() }}
+{% endblock %}
+
+{% block mediagoblin_content -%}
+
+
+ {{ object_gallery(request, media_entries, pagination) }}
+
+ {% set feed_url = request.urlgen('mediagoblin.listings.tag_atom_feed',
+ tag=tag_slug) %}
+ {% include "mediagoblin/utils/feed_link.html" %}
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/submit/collection.html b/mediagoblin/templates/mediagoblin/submit/collection.html
new file mode 100644
index 00000000..4e2bc17d
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/submit/collection.html
@@ -0,0 +1,34 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block mediagoblin_content %}
+
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/collection.html b/mediagoblin/templates/mediagoblin/user_pages/collection.html
new file mode 100644
index 00000000..7ea84876
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/user_pages/collection.html
@@ -0,0 +1,72 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% from "mediagoblin/utils/collection_gallery.html" import collection_gallery %}
+
+{% block mediagoblin_head %}
+
+{% endblock mediagoblin_head %}
+
+{% block title %}
+ {%- trans username=user.username,
+ collection_title=collection.title
+ -%}
+ {{ collection_title }} ({{ username }}'s collection)
+ {%- endtrans %} — {{ super() }}
+{% endblock %}
+
+{% block mediagoblin_content -%}
+
+ {% if request.user and (collection.creator == request.user._id or
+ request.user.is_admin) %}
+ {% set edit_url = request.urlgen('mediagoblin.edit.edit_collection',
+ user=collection.get_creator.username,
+ collection=collection.slug) %}
+ {% trans %}Edit{% endtrans %}
+ {% set delete_url = request.urlgen('mediagoblin.user_pages.collection_confirm_delete',
+ user=collection.get_creator.username,
+ collection=collection.slug) %}
+ {% trans %}Delete{% endtrans %}
+ {% endif %}
+
+ {%- trans collection_description=collection.description -%}
+
+ {{ collection_description }}
+
+ {%- endtrans %}
+
+ {{ collection_gallery(request, collection_items, pagination) }}
+
+ {% set feed_url = request.urlgen('mediagoblin.user_pages.collection_atom_feed',
+ user=user.username,
+ collection=collection.slug ) %}
+ {% include "mediagoblin/utils/feed_link.html" %}
+
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html
new file mode 100644
index 00000000..7499c0cf
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html
@@ -0,0 +1,52 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block mediagoblin_content %}
+
+
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html b/mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html
new file mode 100644
index 00000000..f56ab5ab
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html
@@ -0,0 +1,59 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block mediagoblin_content %}
+
+
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_collect.html b/mediagoblin/templates/mediagoblin/user_pages/media_collect.html
new file mode 100644
index 00000000..a56c9cd3
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/user_pages/media_collect.html
@@ -0,0 +1,88 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block mediagoblin_head %}
+
+{% endblock %}
+
+{% block mediagoblin_content %}
+
+
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/utils/collection_gallery.html b/mediagoblin/templates/mediagoblin/utils/collection_gallery.html
new file mode 100644
index 00000000..a8742c74
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/utils/collection_gallery.html
@@ -0,0 +1,93 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+
+{% from "mediagoblin/utils/pagination.html" import render_pagination %}
+
+{% macro media_grid(request, collection_items, col_number=5) %}
+
+ {% for row in gridify_cursor(collection_items, col_number) %}
+
+ {% for item in row %}
+ {% set media_entry = item.get_media_entry %}
+ {% set entry_url = media_entry.url_for_self(request.urlgen) %}
+
+{%- endmacro %}
+
+{#
+ Render a media gallery with pagination.
+
+ Args:
+ - request: Request
+ - collection_items: cursor of collection items
+ - pagination: Paginator object
+ - pagination_base_url: If you want the pagination to point to a
+ different URL, point it here
+ - col_number: How many columns per row (default 5)
+#}
+{% macro collection_gallery(request, collection_items, pagination,
+ pagination_base_url=None, col_number=5) %}
+ {% if collection_items and collection_items.count() %}
+ {{ media_grid(request, collection_items, col_number=col_number) }}
+
+ {% if pagination_base_url %}
+ {# different url, so set that and don't keep the get params #}
+ {{ render_pagination(request, pagination, pagination_base_url, False) }}
+ {% else %}
+ {{ render_pagination(request, pagination) }}
+ {% endif %}
+ {% else %}
+
+
+ {%- trans -%}
+ There doesn't seem to be any media here yet...
+ {%- endtrans -%}
+
+
+ {% endif %}
+{% endmacro %}
diff --git a/mediagoblin/templates/mediagoblin/utils/collections.html b/mediagoblin/templates/mediagoblin/utils/collections.html
new file mode 100644
index 00000000..feb5dac6
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/utils/collections.html
@@ -0,0 +1,42 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#}
+
+{% block collections_content -%}
+
{% trans collected=media.collected %}In collections ({{ collected }}){% endtrans %}
+
+ {% for collection in media.collections %}
+ {% if loop.last %}
+ {# the 'and' should only appear if there is more than one collections #}
+ {% if media.collections|length > 1 %}
+ ·
+ {% endif %}
+ {{ collection['title'] }}
+ {% elif loop.revindex == 2 %}
+ {{ collection['title'] }}
+ {% else %}
+ {{ collection['title'] }} ·
+ {% endif %}
+ {% endfor %}
+